【问题标题】:How to pass subroutine names as arguments in Fortran?如何在 Fortran 中将子例程名称作为参数传递?
【发布时间】:2015-09-27 15:46:44
【问题描述】:

将子例程名称作为参数传递的语法是什么?示意图:

  .
  .
call action ( mySubX ( argA, argB ) )
  .
  .

subroutine action ( whichSub ( argA, argB ) )
  ...
call subroutine whichSub ( argA, argB )
  ...
end subroutine action

目标是让call subroutine whichSub ( argA, argB ) 充当call subroutine mySubX ( argA, argB )。 我的偏好是避免传递开关参数,然后使用 SELECT CASE。

【问题讨论】:

  • Fortran 的风格和版本是什么?

标签: fortran subroutine


【解决方案1】:

是的

call action(mySubX)

提供的动作看起来像

subroutine action(sub)
  !either - not recommmended, it is old FORTRAN77 style
  external sub
  !or - recommended
  interface
    subroutine sub(aA, aB)
      integer,intent(...) :: aA, aB
    end subroutine
  end interface
  ! NOT BOTH!!

  call sub(argA, argB)

如果action 知道在argA, argB 那里放什么来代表aA, aB

否则,如果您还想传递参数

call action(mySubX, argA, argB)

subroutine action(sub, argA, argB)
  !either - not recommmended, it is old FORTRAN77 style
  external sub
  !or - recommended
  interface
    subroutine sub(aA, aB)
      integer,intent(...) :: aA, aB
    end subroutine
  end interface

  integer, intent(...) :: argA, argB

  call sub(argA, argB)

我不认为在这里使用函数指针是好的,当你有时不得不改变指针(它指向的子程序)的值时它们是好的。普通过程参数在 FORTRAN77 中有效,并且即使现在也继续有效。


所以按照评论中的要求,如果你在一个模块中并且可以从模块中访问具有正确接口的过程(可能在同一个模块中),你可以使用过程语句来获取接口块的棒:

module subs_mod
contains
  subroutine example_sub(aA, aB)
    integer,intent(...) :: aA, aB
    !the real example code
  end subroutine
end module

module action_mod
contains

  subroutine action(sub)
    use subs_mod
    procedure(example_sub) :: sub

    call sub(argA, argB)
  end subroutine
end module

但更有可能的是,您将创建一个抽象接口,而不是一个真正的子例程,您将使用过程语句引用该接口,因此最终一切都将与以前相似:

module action_mod

  abstract interface
    subroutine sub_interface(aA, aB)
      integer,intent(...) :: aA, aB
    end subroutine
  end interface

contains

  subroutine action(sub)
    procedure(sub_interface) :: sub

    call sub(argA, argB)
  end subroutine
end module

【讨论】:

  • 很好的解释。感谢您提供有关现代使用语言和函数指针的提示。我们可以使用模块来避免 INTERFACE 吗?
  • 如果某些模块可以访问某些兼容的过程,您可以使用procedure(mySubX) :: sub。您还可以在模块中为其创建一个抽象接口,并使用相同的procedure(nameOfTheInterface)
  • 也许我记错了,但我的印象是 external 关键字只在调用者(使用过程参数调用的函数)中需要,而不是被调用者。否则,根据 12.4.2 (Fortran 2008),它有一个隐式接口。在 5.3.9#2 中:“如果将外部过程或虚拟过程用作实际参数或作为过程指针分配的目标,则应声明它具有 EXTERNAL 属性。”仅在特殊情况下在被调用方中强制执行(基本上就是接口利用了 F90+ 的特性)。
  • 但是,我同意在这种情况下使用抽象接口和模块要好得多。
【解决方案2】:

我认为使用模块来避免interface 是一种很好的现代 Fortran 实践,因为它提供了更简洁的界面。

这是实现的理想:

模块部分:

module foo
contains

subroutine callsub(sub,arg1,arg2)
!This subroutine is used to call other subroutines
external::sub !Use external to tell compiler this is indeed a subroutine
call sub(arg1,arg2)
end subroutine

subroutine sub(arg1,arg2)
!The subroutine to be called.
!do something
end sub

end module

然后这里是主程序:

program main
use foo !Use module automatically avoids using interface.
implicit none
!Declare about args
call callsub(sub,arg1,arg2)
end program

这里是my demonstration,以准确展示如何实现这一点。

【讨论】:

  • 虽然理论上可以回答这个问题,但这里应该是preferable to include the essential parts of the answer,并提供链接以供参考。
  • 感谢您的纠正。我是这里的新手,我还在学习礼仪。我添加了更多与问题更具体的内容。
  • 干得好,这是一个更好的答案,欢迎来到 Stackoverflow!
  • 嗯,这种设计确实 消除了对接口块的需要,但子程序传递的重点是您可以传递任何 子程序。现在您在主程序中有sub显式接口,但在callsub 中没有。在现代 Fortran 中使用 procedure(sub) 而不是 external 会更好。然后你可以在模块中只拥有一个抽象接口而不是整个sub。然后你意识到你又在一个界面块......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-18
  • 2015-12-09
  • 2018-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多