【问题标题】:Difference between subroutine inside module "contains" and outside module模块内部的子程序“包含”和外部模块之间的区别
【发布时间】:2020-12-30 14:29:28
【问题描述】:

我有一个大型源代码,其中模块中的子例程module ... end module 语句之外定义(即不在contains 语句内部)。我在下面包含了一个简化的模块:

module core
  implicit none

  type :: disc_status
    sequence

    real*8 :: alpha1, alpha2, alpha3

  end type disc_status
end module core

subroutine tester(input)
  use core
  type(disc_status), intent(in) :: input
  print *, input%alpha1, input%alpha2, input%alpha3
end subroutine tester

这是一个使用模块和子程序的示例程序:

program flyingDiscSimulator

use core
implicit none

type(disc_status) :: disc

disc%alpha1 = 1.1D0
disc%alpha2 = 1.2D0
disc%alpha3 = 1.3D0

call tester(disc)

print *, 'it works'

end program flyingDiscSimulator

通常,我最终会看到子例程在模块中使用 contains 语句:

module core
  implicit none

  type :: disc_status
    sequence

    real*8 :: alpha1, alpha2, alpha3

  end type disc_status

   contains
     subroutine tester(input)
       type(disc_status), intent(in) :: input
       print *, input%alpha1, input%alpha2, input%alpha3
     end subroutine tester

end module core

但是,上面引用的程序文件不需要任何更改即可使用在模块中包含子例程的任何一种方式(无论如何都使用 gfortran)。因此,两种解决方案之间的模块或子程序的使用似乎没有区别。 这两种风格之间是否存在“幕后”差异?

【问题讨论】:

    标签: fortran


    【解决方案1】:

    版本

    module m
    contains
      subroutine s()
      end subroutine s
    end module m
    

    module m
    end module m
    
    subroutine s()
    end subroutine s
    

    说完全不同的东西,但在问题的情况下,最终结果大体相同。

    这里的第一个版本创建了一个 模块过程 s 与主机 m;第二个版本有一个外部过程 s,没有主机。

    虽然问题的例子有使用模块的外部过程,但更普遍的区别是:模块过程可以访问模块中的所有实体(除非通过@ 987654327@ 语句或被本地名称所掩盖;使用该模块的外部过程只能访问那些 public 实体。

    但是,来到主程序的效果是不同的。外部子例程及其名称是 global 实体。转到我的第二个版本,然后

    program main
      call s
    end program
    

    是调用外部子程序s 的有效程序。这个子例程引用是有效的,因为主程序中s隐式接口 就足够了。如果外部子程序s 需要显式接口,则此处的主程序将不被允许。在主程序中有一个external s 语句是可以接受的,但不是必须的,以向读者强调子程序是一个外部程序(具有隐式接口)。 (implicit none external 将使external s 成为必要。)

    问题的例子是这样一个显式接口is not required

    模块过程在可访问时始终具有可用的显式接口。但是,模块过程不是全局实体,其名称也不是全局标识符。

    在底层,存在实现差异(源于上述):最值得注意的是编译器通常会“命名”模块过程。

    总之,这两种问题的处理方式是有区别的,但是在这种情况下程序员不会注意到它们。

    【讨论】:

    • 检查我的理解:所以在我的示例程序中,use core 语句完全不需要访问子例程tester,是吗?或者反过来说,testercore 模块除了碰巧在同一个文件中之外,没有任何联系?
    • use corecontains 版本中是必需的,而在其他版本中则不需要。外部子程序和模块之间存在联系:子程序依赖于模块。在同一个文件中没有提供任何语法信息:除了编译顺序和额外文件之外,没有任何区别。 (请注意,use core 实际上在两个版本中都是必需的。您需要它与非contains 版本一起提供参数类型的定义。没有disc_status 依赖项,您将不需要该模块。)跨度>
    【解决方案2】:

    模块内的过程将有一个显式接口(也就是编译器知道参数的特征)。 而模块外部的过程将有一个隐式接口(也就是编译器必须对参数做出假设)。

    显式接口有助于编译器发现编程错误,因此是有利的。 有关优势的更深入讨论,请参见 this answer


    testercore 之外定义时,我什至不确定在程序内部调用tester 是否有效?

    use core 行应该只是让模块的公共对象已知并且测试程序需要它自己的external tester 行。

    【讨论】:

    • 是的,我也不确定它是否是有效的 Fortran,这就是为什么我试图弄清楚它是如何工作的。原始代码已经在许多平台上使用和修改了几年,并且似乎没有任何问题(即,使用许多不同的编译器和几代编译器)。
    猜你喜欢
    • 2012-10-02
    • 1970-01-01
    • 1970-01-01
    • 2013-06-13
    • 1970-01-01
    • 2013-11-05
    • 2014-05-20
    • 2013-06-19
    • 2013-11-29
    相关资源
    最近更新 更多