Fortran 中的 INTERFACE 块和 MODULE 过程之间的区别是啥?

Posted

技术标签:

【中文标题】Fortran 中的 INTERFACE 块和 MODULE 过程之间的区别是啥?【英文标题】:Which is the diffeence between an INTERFACE block and a MODULE procedure in fortran?Fortran 中的 INTERFACE 块和 MODULE 过程之间的区别是什么? 【发布时间】:2013-11-15 20:50:15 【问题描述】:

我对在模块内使用接口块以及使用 CONTAINS 语句为模块内的过程创建“显式接口”感到有点困惑。

我通常使用模块内的接口块编写程序。例如,

    MODULE ModExample
    INTERFACE 
        SUBROUTINE Sumatory(a, b, c)
            IMPLICIT NONE

            INTEGER, INTENT(IN)::a
            INTEGER, INTENT(OUT)::b
            INTEGER, INTENT(OUT)::c
        END SUBROUTINE Sumatory
    END INTERFACE
    END MODULE ModExample

   SUBROUTINE Sumatory(a, b, c)
      IMPLICIT NONE

      INTEGER, INTENT(IN)::a
      INTEGER, INTENT(OUT)::b
      INTEGER, INTENT(OUT)::c

      !Executable statements here

   END SUBROUTINE Sumatory

这对我有用。但也可以使用模块内的 CONTAINS 语句来编写,实际上这就是我查阅过的 Fortran 书籍中编写示例过程的方式。

MODULE ModExample

CONTAINS

SUBROUTINE Sumatory(a, b, c)
    IMPLICIT NONE

    INTEGER, INTENT(IN)::a
    INTEGER, INTENT(OUT)::b
    INTEGER, INTENT(OUT)::c

    !Executable statements here

END SUBROUTINE Sumatory
END MODOULE ModExample

那么 INTERFCE 块有什么问题?两者都是等效的构造吗?我应该使用这两种方法中的哪一种?也许所有这些问题都可以用一个很大的“视情况而定”来回答,但我希望你能解释一下它们的区别。提前致谢。

【问题讨论】:

【参考方案1】:

这取决于,但除非你有很好的相反理由,否则请使用模块过程(“在包含之后”)。

第一种方法的“错误”是您必须两次指定过程的接口 - 一次在接口块中,一次在过程定义本身中。在第二种情况下,接口只指定一次 - 在过程定义中。需要维护多个规范是潜在的错误来源。

详细说明:

在第一个代码示例中,后面的 SUBROUTINE 和 END SUBROUTINE 语句之间的源(不在接口块内)是所谓的外部子程序。这本身就是一个程序单元。外部子程序定义了一个外部过程

在第二个代码示例中,位于模块中 CONTAINS 语句之后的 SUBROUTINE 和 END SUBROUTINE 语句之间的源是一个模块子程序。它是模块程序单元的一部分。该模块子程序定义了一个模块过程

(“子程序”指的是源代码构造,而过程指的是源代码定义的东西。)

还存在定义内部过程的内部子程序(它们出现在主机外部或模块子程序或主程序内的 CONTAINS 语句之后)和单独的模块子程序,这是定义模块过程的另一种方式。

Fortran 程序单元(主程序、模块、子模块、外部子程序、块数据)使用单独编译的模型。当编译一个特定的程序单元时,编译器的行为就好像它忽略了程序中的任何其他程序单元,相反,除非在源代码中明确说明。

这样做的一个后果是,如果您在范围内引用外部过程而没有明确告诉编译器该外部过程是什么样的,那么编译器必须从引用的方式隐式推导出外部过程的接口(过程有一个隐式接口)。以这种方式引用的过程不能使用该语言的许多较新的参数传递特性(因为编译器不知道如何正确调用和传递参数给过程)。实际上,编译器也不太可能识别参数类型不匹配等错误。

接口块,例如第一个代码示例中的接口块,可用于显式指定外部过程的接口。对源代码中可访问 显式接口 的外部过程的引用可以使用所有现代参数传递功能,并且可能会获得更好的编译器错误检测。但是,程序员仍然有责任确保接口体的相关特征与实际的外部过程定义保持一致。

该语言还要求在一个作用域单元中只能访问一个过程的接口。在定义它的外部子程序内部,过程的接口已经是显式的,因此程序员有责任确保同一外部过程的接口主体在外部过程内部不可访问。

允许在程序单元之间共享信息的显式规范之一是 USE 语句,它使有关模块定义的事物的知识在 USE 语句出现的范围内可用。这包括有关模块定义或声明的过程的知识。

(该语言要求模块的公共部分的源代码在使用模块之前“可用”,这实际上意味着必须在编译模块的 USE 语句之前编译模块的源代码。 )

与外部过程不同,模块过程或内部过程的接口在其标识符可访问的范围内始终是显式的 - 不需要为模块过程或内部(除了单独的模块子程序,您不能有接口体)。

总结:

第一个例子 - 你有一个带有外部过程接口主体的模块,然后是外部过程本身。您可以在不需要 USE 模块的情况下引用该外部过程,在这种情况下使用隐式接口(功能有限,容易出错)。或者,如果模块在引用范围内使用,则接口将是显式的。在这种情况下,程序员必须确保接口主体和外部过程定义匹配,并且外部过程的接口主体在外部过程内部不可访问。这很容易出错并且很麻烦。

第二个例子——你有一个模块,它有一个模块过程。如果不使用相关模块,则无法通过其名称引用模块过程。这种引用的接口将始终是显式的。无需为过程维护单独的接口主体。

对我们来说,第一种形式优于第二种形式的唯一充分理由是,如果您需要打破编译依赖循环或以其他方式限制较长的编译依赖链。

【讨论】:

使用接口主体的另一个原因是描述您没有 Fortran 源代码的代码,例如您通过 ISO C 绑定调用的 C 代码。 我没有意识到即使没有使用声明 INTERFACE 块的模块,我仍然可以调用该过程。

以上是关于Fortran 中的 INTERFACE 块和 MODULE 过程之间的区别是啥?的主要内容,如果未能解决你的问题,请参考以下文章

0507 构造代码块和static案例,接口interface

Fortran中的“%”是什么意思/做什么?

AppDelegate.m 类中的@interface 错误

通过在 C++ 接口周围创建 C 包装器,在 FORTRAN 中调用 C++ dll 文件 [关闭]

fortran77 长语句如何换行

从 Fortran 中的 HDF 文件中读取长度未知的数组