【问题标题】:passing allocated array from subroutine to the main program in fortran; use or module? interface?将分配的数组从子程序传递到 fortran 中的主程序;使用还是模块?界面?
【发布时间】:2020-12-05 10:14:02
【问题描述】:

我想在子程序中分配一个数组,然后在主程序中使用这个数组并将它传递给其他子程序。过去(F77?)传递可以在一个公共块中完成,但现在更受欢迎的过程似乎是使用一个模块。当我尝试这个时,如代码示例中所示,编译器会告诉我

Rank mismatch in argument ‘f’ at (1) (scalar and rank-1)

显然,主程序认为 'f' 是一个标量:但是,我读到这段代码的意思是,我在子程序和主程序中都将它声明为一维数组。我错过了什么?

我已经尝试过变体,例如将变量声明为模块的一部分,但我想不出任何办法使编译没有错误(而且有些产生了更多错误 ;-( )。任何见解都非常感谢。

          module subs
        contains
        subroutine makef(f)
        end subroutine makef
      end module subs
c-----------------------------------------------------------------------
      program work

      use subs
      implicit none
        real, allocatable :: f(:)

      call makef(f)

      write (*,*) f
      stop
      end
c---------------------------------------------------------------------
      subroutine makef(f)
      implicit none

      real, allocatable, intent(out) :: f(:)
      integer :: i
      integer :: is

      is=10
      allocate(f(-is:is))

      do i=-is,is
        f(i)=i
      end do
      return
      end subroutine makef

【问题讨论】:

  • 对所有 Fortran 问题使用标签 fortran

标签: fortran gfortran


【解决方案1】:

您只将第一行和最后一行的副本放入模块中。那是行不通的。您必须将整个子程序移到模块中。

【讨论】:

    【解决方案2】:

    Fortran 中的模块与其他语言中的头文件不同,后者仅提供有关其他地方定义的事物的信息。有“延迟定义”(子模块)的概念,但在这种情况下,模块应该说明有关子例程的所有内容,而不是简单地试图指出它的存在。

    在问题的例子中,我们有:主程序;带有模块过程makef的模块subs;一个外部子程序makef

    主程序使用模块subs,其过程makef,所以主程序中对makef的引用是指该模块过程而不是外部子程序makef

    模块子例程makef 的参数f 没有声明语句,使其成为隐式声明的标量/外部函数。这是编译器的消息。在模块中使用implicit none,就像这里在主程序和外部子程序中一样。

    子程序的整个定义应该放在模块中:

    module subs
      implicit none
    contains
      subroutine makef(f)
        real, allocatable, intent(out) :: f(:)
        integer :: i
        integer :: is
    
        is=10
        allocate(f(-is:is))
    
        do i=-is,is
          f(i)=i
        end do
      end subroutine makef
    end module subs
    

    另外,如果确实想引用外部过程的后续实现,则可以在模块中使用接口块,而无需声明子例程本身。在这种情况下,仍然需要指定完整的接口:

    module subs
      implicit none
    
    ! An interface block to give an explicit interface to the external subroutine makef
      interface
         subroutine makef(f)
           implicit none
           real, allocatable, intent(out) :: f(:)
         end subroutine makef
      end interface
    end module subs
    

    在这种情况下,不要首选接口块。

    【讨论】:

    • Francescalus 的解决方案有效:通过反复试验,我找到了相同的方法。仅供参考,当我试图了解模块如何工作时,我误读了许多有关我遇到的相关主题的早期帖子。最(恕我直言)误导的一个在模块内部有子程序 a ..... end 子程序 a ,但在我的评论中缺少 .....。我跟着那个信,没有得到任何地方。让弗朗西斯卡卢斯的明确回应成为一个例子,说明如何与可能缺乏必要背景的人进行清晰的沟通,并举一个明确的例子。谢谢。
    • “Fortran 中的模块与其他语言中的头文件不同,它仅提供有关其他地方定义的内容的信息。” 接口模块除外。有了它们,您几乎可以得到与 C 头文件完全相同的内容。
    • @Jean-ClaudeArbaut,可以将接口主体(如最后一个示例)视为有形的东西。现在,一个完全由external 语句组成的模块......
    • @francescalus 是的,我没有注意最后一个例子。这就是我的意思。与在 C 头文件中一样,您声明了函数,这增强了类型安全性。相对于包含实现的模块的好处是 1/ 您不需要访问源代码(例如与 C API 接口:英特尔为 Windows API 提供接口模块),以及 2/ Fortran 二进制对象仍然可以与无法理解模块的软件互操作。我没查,但是相信IMSL的模块接口也是基于这个的,因为老的调用还是可以的。
    • @Jean-ClaudeArbaut,我完全同意带有接口块/主体的模块是完全有效和有用的(作为“为旧的 Fortran 代码、外部过程添加显式接口”或“与实现分离” )。
    猜你喜欢
    • 2017-09-17
    • 2018-01-21
    • 2017-07-19
    • 2013-11-01
    • 2014-04-05
    • 2013-10-28
    • 2012-10-15
    • 1970-01-01
    • 2023-03-14
    相关资源
    最近更新 更多