9

我对在模块内使用接口块以及使用 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 块有什么问题呢?两者都是等效的构造吗?我应该使用这两种方法中的哪一种?也许所有这些问题都可以用一个很大的“视情况而定”来回答,但我希望你能解释一下它们之间的差异。提前致谢。

4

1 回答 1

14

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

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

阐述:

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

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

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

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

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

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

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

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

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

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

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

总之:

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

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

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

于 2013-11-05T04:34:00.493 回答