提问人:AncientSwordRage 提问时间:12/7/2011 最后编辑:CommunityAncientSwordRage 更新时间:9/15/2019 访问量:47253
在 Fortran 中正确使用模块、子程序和函数
Correct use of modules, subroutines and functions in Fortran
问:
我最近在向 Fortran 程序添加函数时了解了接口块。一切正常,但现在我想在接口块中添加第二个函数。
这是我的接口块:
interface
function correctNeighLabel (A,i,j,k)
integer :: correctNeighLabel
integer, intent(in) :: i,j,k
integer,dimension(:,:,:),intent(inout) :: A
end function
function correctNeighArray (B,d,e,f)
character :: correctNeighArray
integer, intent(in) :: d,e,f
character, dimension(:,:,:),intent(inout) :: B
end function
end interface
在我看来,这可能不是最好的选择。
我已经研究了子程序,但我不太相信它是正确的解决方案。我正在做的事情相对简单,我需要将参数传递给子例程,但我见过的所有子例程都是 a) 复杂(即对于函数来说太复杂了),以及 b) 不接受参数。它们的行为就像它们在操作变量而不将变量传递给它们一样。
我还没有真正正确地研究过模块,但从我所看到的情况来看,这不是正确的使用方式。
我应该在什么时候使用哪个,以及如何最好地使用它?
答:
模块始终是正确的使用方式;-)
如果你有一个非常简单的 F90 程序,你可以在 'contains' 块中包含函数和子程序:
program simple
implicit none
integer :: x, y
x = ...
y = myfunc(x)
contains
function myfunc(x) result(y)
implicit none
integer, intent(in) :: x
integer :: y
...
end function myfunc
end program
然后,函数/子例程的接口将在程序中已知,并且不需要在接口块中定义。
对于更复杂的程序,您应该将所有函数/子程序保留在模块中,并在需要时加载它们。因此,您也不需要定义接口:
module mymod
implicit none
private
public :: myfunc
contains
function myfunc(x) result(y)
implicit none
integer, intent(in) :: x
integer :: y
...
end function myfunc
end module mymod
program advanced
use mymod, only: myfunc
implicit none
integer :: x, y
x = ...
y = myfunc(x)
end program advanced
模块和程序可以(实际上应该)在单独的文件中,但模块必须在实际程序之前编译。
评论
mysub
end function myfunc
implicit none
implicit none
附议和扩展已经说过的内容。最好将过程(子程序和函数)放入模块中并“使用”它们,因为它们可以毫不费力地自动检查接口的一致性。其他方法也有缺点。如果使用接口块定义接口,则需要维护三件事,而不是两件事:接口、过程本身和调用。如果进行更改,则必须修改所有三个以保持一致。如果使用一个模块,则只需更改两个模块。使用接口块的一个原因是,如果您无法访问源代码(例如,预编译库)或源代码是另一种语言(例如,您通过 ISO C 绑定使用 C 代码)。
“包含”方法的缺点是,包含的过程继承了父程序的所有局部变量......它不是很模块化,如果您忘记了这个“功能”,可能会非常令人困惑。
alexurba 和 MSB 的答案一如既往地正确和有用;让我再详细一点地充实一点——如果模块是要走的路(而且确实如此),那么接口到底有什么用?
对于模块中的函数和子程序,该模块的任何内容都可以自动看到这些接口;接口是在编译模块时生成的(除其他外,该信息会进入编译模块时生成的 .mod 文件)。所以你不需要自己写。类似地,当你使用一个 ed 子程序时(与 MSB 一致,我发现它更令人困惑而不是有用——它们被认为是闭包或嵌套子程序比外部子程序好得多),主程序已经可以显式地“看到”接口,它不需要你为它写出来。use
CONTAIN
接口块适用于无法执行此操作的情况 - 当编译器无法为您生成显式接口时,或者当您想要与给定的接口不同的东西时。例如,在 Fortran 2003 中使用 C-Fortran 互操作性。在这种情况下,Fortran 代码链接到某个 C 库(比如说),并且无法为您生成指向 C 例程的正确 fortran 接口——您必须通过编写自己的接口块来自己完成。
另一个例子是,当你已经知道子例程的接口时,但当你想创建一个新接口来“隐藏”子例程时——例如,当你有一个对整数进行操作的例程,以及一个对实数进行操作的例程时,你希望能够在任何一个上调用相同的例程名称,并让编译器根据参数对其进行排序。这种构造称为泛型例程,自 Fortran 90 以来一直存在。在这种情况下,您可以显式创建此新泛型例程的接口,并列出该接口块中“实际”例程的接口。
评论