【问题标题】:Structure of a fortran program with modules and subroutines具有模块和子例程的 fortran 程序的结构
【发布时间】:2016-04-13 12:16:07
【问题描述】:

这是主程序的一部分

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

method_init 的调用,包含在模块 method 中,“初始化”了一个方法,它构建数组 a1endC 形成数组 A(对包含在模块应遵循)。 数组a1endC 是方法的一部分,所以它们都在method 模块中声明;数组A 不是方法的一部分(它可以用另一种方法“解决”),所以它在模块variables 中声明。

数组Ca1end 可以被不包含在method 模块中的子例程使用,因此必须在CONTAINS 语句之前声明它们。 因此,method 模块中包含的子例程可以使用这些变量而不将它们用作输入/输出变量,但这会使子例程的作用不清楚(调用将简单地为CALL method_init,所以“这个子例程如何操作?它使用了哪些数组?修改了哪些?..."),所以我更喜欢调用 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

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

编辑简而言之,问题是: 将模块中定义的变量用作模块本身包含的过程的输入/输出参数是一种正确的编程方式吗?还是最好编写不带参数的子程序?还是一切都只是品味问题?

@Vladimir F 链接的问题/答案让我认为是的,这是一个品味问题。尽管如此,这些问题都没有触及我感兴趣的特定点(即模块中的过程并使用模块中定义的变量作为输入/输出参数)。

【问题讨论】:

  • 很久没看FORTRAN了。它伤害了我的眼睛。请阅读常见问题解答,了解哪些问题适用于 SO。基于意见的问题不是,因为它不是一个讨论板。
  • 在我有空的时间内,我无法清楚地遵循您所写的内容,但是您对范围的概念有疑问:本地虚拟变量和模块变量吗?
  • 我不会那样做,可能宁愿使用派生数据类型和程序中直接声明的实际变量,但你的代码是合法的 Fortran。

标签: module scope fortran subroutine


【解决方案1】:

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

然而,很多人在 Fortran 中使用全局变量并且不会费心传递这些参数,有时是出于错误的原因(比如“编写起来更快”)。 但是,如果您将模块中的全局变量想象成一个包含其自己特定且唯一的参数集的框,那么在模块中使用全局变量仍然是完全正确的。也许那时您想将它们指定为 Fortran parameter(带有关联的关键字)。

当您对传递参数或对函数/子例程使用全局变量提出疑问时,一个简单的选择是您的函数是否一定会在其他地方与其他不同的参数一起调用/重用在您的代码中,或稍后在您的开发过程中。 当您将模块视为一个 box 时尤其如此,您可以将其拔出并提供给伴侣以满足他自己的需要,那么您可能希望您的 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

【讨论】:

  • 抱歉,这有点模棱两可,我指的是在子例程/函数之外定义的变量,这里是在一个模块中,因此可以通过use module 在代码中的任何位置访问。
  • @francescalus 这将取决于您选择的“全局变量”定义(它不是 Fortran 术语),但我将可公开访问的未受保护的模块变量称为“全局变量”(同样还有共同的对象块)。因为它们可以在程序的任何地方轻松访问和改变,它们是程序全局状态的一部分(除了多个图像),因此受到通常引用使用全局变量的缺点的影响。标识符不是全局的,但标识符不是变量,它是变量的标识符。
  • @IanH(和 Mathieu Coquerelle)我很乐意接受“全局”来表示模块中的此类变量。只是我可能对不合格的“全球”所指的常见块感到伤痕累累。 [考虑到上下文,这无疑是可笑的:我将删除我无用的评论。]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-24
  • 1970-01-01
  • 2012-01-14
  • 2016-05-22
  • 1970-01-01
相关资源
最近更新 更多