在Fortran中应该把`implicit none`放在哪里?

38

我需要在每个函数和子程序中添加implicit none吗?

还是只需要在包含这些函数和子程序的模块开头添加它就可以了?

还是只需要在使用这些模块的程序开头添加它就可以了?

通过观察别人的工作代码,这些地方都包括了implicit none。不确定是否重复了,因为从子程序中删除implicit none仍然可以编译并产生相同的输出。

顺便说一句,我正在使用gfortran fortran 90

4个回答

33
“implicit”语句(包括“implicit none”)适用于一个作用域单元。这种东西被定义为:
BLOCK结构、派生类型定义、接口体、程序单元或子程序,但不包括其中所有嵌套的作用域单元。
“不包括其中所有嵌套的作用域单元”意味着在模块中定义的每个函数和子例程(统称为过程)中都可能需要/希望使用“implicit none”。然而,在模块内包含的过程中,存在基于“主机”作用域单元的默认映射。因此,在模块中使用“implicit none”就不需要在包含的过程中再次使用。
这个主机作用域规则同样适用于内部程序。这意味着主程序中的“implicit none”覆盖了其中包含的所有过程;对于模块过程的内部程序也是如此。块结构也遵循这一点,而在其中不允许使用“implicit”语句。
然而,外部函数/子程序不会继承程序或模块的隐式行为,而模块也不会从使用它们的程序/其他模块中继承。这显然是有道理的,因为隐式类型必须在编译时知道并且无论其最终用途如何都必须定义清楚。
此外,一个程序单元不能将其隐式规则应用于它使用的模块,例如:
implicit none
use somemodule

end program

一个 implicit 语句必须跟随所有的 use 语句。
同样地,子模块是自身的程序单元,与其祖先不同。模块或子模块是一个父级,而不是扩展它的主机。主机作用域规则不适用于子模块,并且子模块不会从其父级继承映射规则。在子模块的范围内没有 implicit 语句,则默认规则将适用于该范围内。
需要注意的是,主机作用域单位规则不适用于接口体。IanH's answer 解释了这个例外情况,但这是一个重要的事情需要强调。它已经引起了很多混淆。
module mod
 implicit none

  interface
    subroutine external_sub()
      ! The default implicit typing rules apply here unless
      ! there is an implicit statement, such as implicit none.
      ! Those from the module aren't in force here.
    end subroutine
  end interface

end module

关于从子程序中删除implicit none的测试:如果代码使用implicit none是有效的,那么没有该语句时它必须是有效且相同的。在前一种情况下,所有实体都必须明确声明,因此在后一种情况下不会应用任何隐含规则。


你能否稍微改进一下你的回答,写一句话提到程序中包含的函数/子程序与模块中包含的函数/子程序在implicit none方面的工作方式完全相同?非常好的回答。 - NoseKnowsAll

7
不,是,不。每个程序单元(与每个程序不同)和每个接口体中一次足够了。程序单元可以是主程序、模块、外部子程序(不出现在另一类型的程序单元的CONTAINS语句之后的函数或子例程子程序)、块数据程序单元或子模块。除非使用IMPLICIT语句另有规定,在每个程序单元中,默认映射以I-N开头的内容为默认整数,其他所有内容为默认实数。相同的原则适用于接口体-因为它们应该是在另一个程序单元中定义的过程的规范部分的快照。除非另有不同规定,否则该程序单元将具有默认映射,因此接口体具有默认映射。在程序单元内,内部子程序或模块子程序继承其主机中指定的任何隐式类型,如果在子程序本身中没有“本地”IMPLICIT语句。冗余的IMPLICIT NONE规范是无害的。您经常会看到它,其中以前是外部子程序的子程序已被放入模块中。

还有一些现存的FORTRAN 77代码,已经变成了化石;)。它让我的眼睛流血,因为我脑海中浮现出打孔卡片的图像,但你甚至可以在SO上找到很多这样的代码。 - sigma

6
这是一个基于我个人经验的非正式回答。
我的Fortran代码分为两种类型的文件——包含主程序的文件和包含单个模块的文件。在每种文件中,IMPLICIT NONE出现在“program foo”或“module foo”语句之后以及顶部的USE语句之后。它不会出现在子例程或函数内部,因为那将是冗余的。

1
我的帖子中有一个错误,现在已经修复了。我在USE语句之后加了IMPLICIT NONE。我从不使用INCLUDE语句。 - Fortranner

3
如果您使用的是gfortran,可以直接添加-fimplicit-none参数。请注意,这是一种特定于编译器的解决方案。其他广泛使用的编译器可能不支持此参数。例如,Intel的ifort将其忽略为未知选项。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接