在Fortran中正确使用模块,子例程和函数
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Fortran中正确使用模块,子例程和函数相关的知识,希望对你有一定的参考价值。
我最近在向Fortran程序添加函数时学习了tinterface块。一切都很好,整洁,但现在我想在接口块中添加第二个功能。
这是我的界面块:
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
模块和程序可以(实际上应该)在单独的文件中,但模块必须在实际程序之前编译。
借调和扩展已经说过的话。最好将您的过程(子程序和函数)放入模块中并“使用”它们,因为它们可以轻松地对接口进行自动一致性检查。其他方式有缺点。如果使用接口块定义接口,则需要维护三件事而不是两件:接口,过程本身和调用。如果进行更改,则必须修改所有三个以保持一致。如果使用模块,则只需更改两个模块。使用接口块的原因是您无法访问源代码(例如,预编译库)或源代码使用其他语言(例如,您通过ISO C绑定使用C代码)。
“包含”方法的缺点是包含的过程继承了父程序的所有局部变量......这不是非常模块化的,如果你忘记了这个“特性”,可能会非常混乱。
alexurba和MSB的答案像往常一样正确和有用;让我在一点上充实一些细节 - 如果模块是要走的路(它们是),那么什么是接口呢?
对于模块中的函数和子例程,use
s该模块可以自动查看这些接口的任何内容;编译模块时会生成接口(除其他外,该信息会进入编译模块时生成的.mod文件)。所以你不需要自己写。类似地,当你使用CONTAIN
ed子程序(同意MSB,我发现更令人困惑然后有用 - 他们更好地被认为是closures或nested subroutines而不是外部子程序),主程序已经可以明确地“看到”界面了它不需要你为它写出来。
接口块用于当您无法执行此操作时 - 编译器无法为您生成显式接口,或者您需要的内容与给定的内容不同时。一个例子是在Fortran 2003中使用C-Fortran interoperability。在这种情况下,Fortran代码链接到一些C库(比如说)并且无法为您生成正确的C语言例程 - 您必须自己完成,通过编写自己的接口块。
另一个例子是当你已经知道子程序的接口时,但是当你想要创建一个新的接口来“隐藏”后面的子程序时 - 例如,当你有一个例程在(比如说)整数上运行时,一个在reals上运行,并且您希望能够在任一个上调用相同的例程名称,并让编译器根据参数对其进行排序。这样的结构被称为generic routines,并且自Fortran 90以来就已存在。在这种情况下,您可以显式创建一个接口来实现这个新的通用例程,并将接口列出到该接口块中的“真实”例程。
以上是关于在Fortran中正确使用模块,子例程和函数的主要内容,如果未能解决你的问题,请参考以下文章
使用 GCC 对模块内的 fortran 子例程进行外部命名