在Fortran中正确使用模块

rks*_*171 4 fortran module function subroutine

我与FORTRAN合作很多,但我从来没有正确的指令来编写源代码.我目前使用模块来存储全局变量,但我知道你也可以使用它们来存储子程序和函数.我使用的代码有很多子程序,因为它们非常庞大和复杂.所有功能和子程序都应该在模块中吗?如果是这样,为什么?

Hig*_*ark 20

一般来说,你的第一个问题的答案是肯定的,我马上就会回答你的第二个问题.首先要注意的是,这是对一般问题的一般答案,并且围绕SO Fortran问题的明亮火花可能会提出模块不适用的特殊情况.我事先反驳说,这个答案是针对模块的新手.一旦您不再是新手,您就可以制定自己的问题答案.

模块对程序员最有用,可以帮助组织和构建程序或程序套件.它们提供了一种机制,用于封装用户定义类型的定义以及对这些类型进行操作的函数/子例程.在Fortran 90和95中,这种封装在某种程度上是临时性的,因为它依赖于程序员关于如何将程序分解为部分的想法.随着Fortran 2003中面向对象设施的引入,现在有更清晰的"规则"来识别每个模块中的元素.

例如,您可以设想一个用于理性算术的类型和过程的模块.通过在一个模块中保留实现您的好主意的所有代码,您可以隐藏程序其他部分的实现(不需要知道详细信息)并仅公开您希望公开的部分(查看PRIVATEPUBLIC关键字) .您可以立即看到将代码组织到模块中的另一个好处; USE在新程序中使用合理的算术模块要比将大型源文件中的代码剪切并传递到另一个大型源文件要容易得多.当您想要进行理性算术时,您需要在一个模块中处理代码,而不是在遍布文件的代码中进行处理.

模块还允许您管理名称冲突.例如,您的有理算术模块可能会定义一个被调用的操作add,您可能还有一个多精度整数算术模块,它定义了一个被调用的操作add.如果您USE在程序(或其他模块)中尝试这两个模块,则编译器将警告(可能引发错误)在使用模块的范围内定义相同的名称两次.使用关联模块实体时,可以使用重命名.您还可以使用ONLY子句仅导入用户需要的那些模块实体.

请注意,模块USE是可传递的,如果A使用B而B使用C,则您不必声明A使用C(尽管如果您已重命名实体或指定的ONLY子句,则必须确保在特定的内容中具有传递性案件).

简而言之,模块是Fortran的主要机制,通过将程序分解为可管理的块来处理程序的复杂性.Fortran 2008,当该功能由编译器实现时,也引入了SUBMODULEs,它承诺更好地支持以这种方式处理复杂性.

模块也很有用,因为语言标准要求编译器生成模块中定义的过程的显式接口,以便在编译时对参数进行类型检查.请注意,这些接口(您从未真正看到过)被称为显式,以与隐式接口形成对比,隐式接口是未在模块内部定义CONTAIN的程序(或在使用它们的程序单元内编辑的程序).当然,您可以为此类过程编写显式接口,但在短期和长期运行中,让编译器为您执行此操作几乎总是更容易.

正如@Telgin已经指出的那样,模块也有助于增量编译.


Chr*_*ris 6

使用模块的一个主要好处是,您的编译器将自动对use模块中的任何函数或子例程执行接口检查,以确保您使用适当的参数类型调用例程.关于这个主题的一篇好文章是Fortran博士获得明确 - 再次!.从这篇文章:

有几种方法可以提供显式接口.最简单和最好的方法是将过程放在模块中,或使其成为调用程序或过程的CONTAINed过程.这样做的好处是不需要您两次写入信息,从而增加了在其中一个地方出错的可能性.当您具有模块过程或包含的过程时,其界面将自动对模块中的所有其他过程或父范围内可见.假设该名称尚未声明为PRIVATE,则该接口也可用于您使用包含模块过程的模块的位置.

我建议将所有相关例程放在同一个模块中.对我来说,模块相当于其他语言中的类.模块是一种对相关数据和例程(可以对该数据进行操作)进行分组的方法.因此,如果您的例程按逻辑分组到模块中,并为您的函数和子例程调用添加类型检查,那么模块提供了一种使代码更易于导航的方法.