具有模块和子例程的 Fortran 程序的结构

Structure of a fortran program with modules and subroutines

这是主程序的一部分

PROGRAM program1
USE method
USE variables
IMPLICIT NONE
:
CALL method_init(A,a1end,C)
:
END PROGRAM program1

method_init 的调用,包含在模块 method 中,"initializes" 一种构建数组 a1endC 形成数组的方法A(应遵循对模块中包含的其他过程的其他调用)。 数组 a1endC 是方法的一部分,因此它们都在 method 模块中声明;数组 A 不是方法的一部分(它可能是 "solved" 与另一个方法),因此它在模块 variables.

中声明

数组 Ca1end 可以被不包含在 method 模块中的子程序使用,所以它们必须在 之前声明 CONTAINS 语句。 因此,包含在 method 模块中的子例程可以使用这些变量而不将它们用作 input/output 变量,但这会使子例程的作用不明确(调用将只是 CALL method_init,所以 "How does this subroutine operate? Which arrays does it use? And which modify? ..."), 所以我更喜欢将呼叫作为 CALL method_init(A,a1end,C).

这意味着模块method是这样的

MODULE method
    IMPLICIT NONE
    REAL, DIMENSION(:,:), ALLOCATABLE :: C     ! declared here to be used...
    REAL, DIMENSION(:,:), ALLOCATABLE :: a1end ! ...by procedures outside this module
    :
CONTAINS
    SUBROUTINE method_init(A,a1end,C)
    IMPLICIT NONE
    REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(IN) :: A ! deferred shape (it's allocated elsewhere in the main program)j
    REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: C     ! declared here to be used...
    REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: a1end ! ...as input/output variables
    :
    ALLOCATE(C(  ),a1end(   ))
    :
    END SUBROUTINE method_init
END MODULE method

我想知道这是否是一种正确的编程方式。这只是品味问题吗?

EDIT 简而言之,问题是: 使用模块中定义的变量作为模块本身包含的过程的 input/output 参数是否是正确的编程方式?还是编写不带参数的子程序更好?或者一切都只是品味问题?

@Vladimir F 链接的 questions/answers 让我觉得是的,这是一个品味问题。尽管如此 none 这些问题触及了我感兴趣的具体点(即模块中的过程并使用模块中定义的变量作为 input/output 参数)。

我的回答是您做出了正确的选择,因为我总是建议编写包含所有参数的过程并避免使用 全局变量(例如 Ca1end 在你的例子中)。

然而,Fortran 中的许多人习惯于使用全局变量并且不会费心传递这些参数,有时是出于错误的原因(例如 "it's faster to write")。 但是,如果您将模块想象成一个包含其自己特定且唯一的参数集的盒子,那么在模块中使用全局变量仍然是完全正确的。也许那时您会希望将它们指定为 Fortran parameter(带有关联的关键字)。

当您质疑自己传递参数或使用 全局变量 作为 function/subroutine 时,一个简单的选择是您的函数是否绑定为 called/reused 在代码的其他地方或开发过程中的某个时间使用其他不同的参数。 当您将您的模块视为一个 盒子 时尤其如此,您可以拔下插头并根据自己的需要提供给伴侣,那么您可能希望您的 method_init 更灵活,从而明确论点。

注意:在您的示例中,我建议以不同于模块变量的方式命名您的子例程参数,以避免代码中的任何混淆并能够在没有任何冲突的情况下使用它们:

MODULE method
    IMPLICIT NONE
    REAL, DIMENSION(:,:), ALLOCATABLE :: C
    REAL, DIMENSION(:,:), ALLOCATABLE :: a1end 

CONTAINS

    SUBROUTINE method_init(A,my_a1end,my_C)
    IMPLICIT NONE ! Already specified above
    REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(IN) :: A
    REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: my_C
    REAL, DIMENSION(:,:), ALLOCATABLE, INTENT(OUT) :: my_a1end
    ALLOCATE(my_C(  ),my_a1end(   ))
    ! Here you can work with module's C and a1end
    ! Given that they have been effectively allocated
    ! You can also test whether C and my_C are the same object or not (pointerwise speaking)
    END SUBROUTINE method_init
END MODULE method