在Fortran中正确使用模块,子例程和函数

时间:2011-12-07 09:15:17

标签: function module fortran fortran90 subroutine

我最近在向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)不接受参数,它们表现得好像他们操纵变量而不将它们传递给它们。

我没有真正研究过模块,但从我所看到的不适合使用模块。

我应该在何时使用,以及如何最好地使用它?

3 个答案:

答案 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,我发现更多令人困惑然后有帮助 - 他们被认为比closuresnested subroutines好于外部子程序) ,主程序已经可以明确地“看到”界面,并且它不需要你为它写出来。

接口块适用于无法执行此操作的情况 - 当编译器无法为您生成显式接口时,或者您需要的内容与给定的内容不同时。一个例子是在Fortran 2003中使用C-Fortran interoperability时。在这种情况下,Fortran代码链接到一些C库(比方说)并且无法为您生成正确的Fortran接口到C例程 - 你有通过编写自己的接口块来自己完成。

另一个例子是当你已经知道子程序的接口时,但是当你想要创建一个新的接口来“隐藏”后面的子程序时 - 例如,当你有一个例程对(例如)整数进行操作时,一个在reals上,你希望能够在任一个上调用相同的例程名称,让编译器根据参数对其进行排序。这样的构造被称为generic routines,并且自Fortran 90以来就已存在。在这种情况下,您将为此新的通用例程显式创建一个接口,并将接口列出到该接口块中的“真实”例程。