我最近在向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)不接受参数,它们表现得好像他们操纵变量而不将它们传递给它们。
我没有真正研究过模块,但从我所看到的不适合使用模块。
我应该在何时使用,以及如何最好地使用它?
答案 0 :(得分:39)
模块始终是正确的选择; - )
如果你有一个非常简单的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
模块和程序可以(实际应该)在单独的文件中,但模块必须在实际程序之前编译。
答案 1 :(得分:17)
借调和扩展已经说过的话。最好将您的过程(子程序和函数)放入模块中并“使用”它们,因为它们可以轻松地对接口进行自动一致性检查。其他方式有缺点。如果使用接口块定义接口,则需要维护三件事而不是两件:接口,过程本身和调用。如果进行更改,则必须修改所有三个以保持一致。如果使用模块,则只需更改两个模块。使用接口块的原因是,如果您无法访问源代码(例如,预编译的库),或者源代码使用其他语言(例如,您通过ISO C绑定使用C代码)。
“包含”方法的缺点是包含的过程继承了父程序的所有局部变量...这不是非常模块化的,如果你忘记了这个“功能”,可能会非常混乱。
答案 2 :(得分:16)
alexurba和MSB的答案像往常一样正确和有用;让我在一点上充实一点细节 - 如果模块是要走的路(它们是什么),那么什么是接口呢?
对于模块中的函数和子例程,use
该模块可以自动查看这些接口的任何内容;编译模块时会生成接口(除其他外,该信息会进入编译模块时生成的.mod文件)。所以你不需要自己写。类似地,当你使用CONTAIN
ed子程序(同意MSB,我发现更多令人困惑然后有帮助 - 他们被认为比closures或nested subroutines好于外部子程序) ,主程序已经可以明确地“看到”界面,并且它不需要你为它写出来。
接口块适用于无法执行此操作的情况 - 当编译器无法为您生成显式接口时,或者您需要的内容与给定的内容不同时。一个例子是在Fortran 2003中使用C-Fortran interoperability时。在这种情况下,Fortran代码链接到一些C库(比方说)并且无法为您生成正确的Fortran接口到C例程 - 你有通过编写自己的接口块来自己完成。
另一个例子是当你已经知道子程序的接口时,但是当你想要创建一个新的接口来“隐藏”后面的子程序时 - 例如,当你有一个例程对(例如)整数进行操作时,一个在reals上,你希望能够在任一个上调用相同的例程名称,让编译器根据参数对其进行排序。这样的构造被称为generic routines,并且自Fortran 90以来就已存在。在这种情况下,您将为此新的通用例程显式创建一个接口,并将接口列出到该接口块中的“真实”例程。