在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的答案像往常一样正确和有用;让我在一点上充实一些细节 - 如果模块是要走的路(它们是),那么什么是接口呢?

对于模块中的函数和子例程,uses该模块可以自动查看这些接口的任何内容;编译模块时会生成接口(除其他外,该信息会进入编译模块时生成的.mod文件)。所以你不需要自己写。类似地,当你使用CONTAINed子程序(同意MSB,我发现更令人困惑然后有用 - 他们更好地被认为是closuresnested subroutines而不是外部子程序),主程序已经可以明确地“看到”界面了它不需要你为它写出来。

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

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

以上是关于在Fortran中正确使用模块,子例程和函数的主要内容,如果未能解决你的问题,请参考以下文章

使用 GCC 对模块内的 fortran 子例程进行外部命名

使用 GCC 对模块内的 fortran 子例程进行外部命名

fortran 模块的子例程名称冲突

C++ 从 dll 调用 FORTRAN 子例程

使用宏的 Fortran 替换子例程名称

如何将可分配数组传递给 Fortran 中的子例程