4

目前在我的程序中,我有几个公共块分布在几个子程序和函数中。当我向其中添加变量时,我有时会忘记更改公共块的所有实例。我想将这些公共块制作成模块,这样我就可以在一个地方向模块添加和删除变量,而不必担心在我的子程序中更新模块的所有实例。

我是否需要在初始化模块中的变量的程序中包含“使用”语句,或者我是否需要在模块中包含程序?我通常会为此使用通用块,但我正在尝试实现模块,因为我认为随着复杂性的增加,它们将帮助我的代码保持可读性。

注意:模块中变量的某些值需要能够在它们从一个程序传递到另一个程序时进行更改。

我试图编写一个简化的测试程序来熟悉模块,但无法让它工作。我熟悉 fortran 77,但以前从未使用过模块。我感谢任何帮助或建议。

我正在使用 gfortran 4.6.1

主文件

program main
use Words
use Vals
double precision x,y,z
character*5 Greet
integer i

Greet = 'Hello'
x = 4.1
y = 5.2
z = 10.0
i = 3

call foo ()

end program main

subroutine foo ()
use Words
use Vals

print *, Greet

z = x + y
print *, z

print *, i

end subroutine

module Words
character*5 Greet
save
end module

module Vals
double precision x,y
integer int
save
end module
4

3 回答 3

5

您只需要一个模块实例。use你让任何使用它和语句的主程序或过程(子程序或函数)都知道它。如果您有一个设置值的子例程,那么与其他任何例程一样,它必须有一个use语句。如果要设置初始值,您可以在声明中这样做。如果模块被主程序使用,那么它将始终在范围内,并且变量的值将在整个程序运行期间保持不变。如果模块仅由过程使用,原则上,当调用链中没有这些过程时,模块将超出范围,并且允许编译器忘记模块变量的值。(任何 Fortran 编译器实际上都这样做是值得怀疑的。)这可以通过用 . 声明每个变量来防止SAVESAVE如果您使用初始值声明变量,则为隐式。

通常,您必须在使用模块之前先编译模块,以便编译器在遇到 use 语句时“知道”它们。这可以通过将它们放在文件中的第一位或先编译它们的文件来完成。这是您重新排序的示例:

module Words
character*5 Greet
save
end module

module Vals
double precision x,y
integer i
save
end module

module my_subs

contains

subroutine foo ()
use Words
use Vals
double precision :: z

print *, Greet

z = x + y
print *, z

print *, i

end subroutine

end module my_subs


program main
use Words
use Vals
use my_subs


Greet = 'Hello'
x = 4.1
y = 5.2

i = 3

call foo ()

end program main
于 2013-01-10T16:54:53.603 回答
1

您的代码无法编译的原因有几个:

  1. 你的模块位于你的主程序之后,这意味着当你在那里时use它们还没有被编译。要么将它们放在单独的文件中并在主程序之前编译它们,要么将它们放在主程序之前。

  2. 您在主程序中从模块中重新声明变量,编译器会将其解释为名称冲突。所有具有该属性的模块变量public(这是默认值)都将在use模块所在的范围内可用;这称为“使用关联”。换句话说,use vals足以使xy并且int可用。

此外,模块更像是单例对象,而不仅仅是数据容器。它们还可以包含在contains语句之后列出的过程,这有助于将变量和相关过程组合在一起。一个示例是将您的两个模块与 subroutine 一起分组为一个foo

module vals
  implicit none

  double precision :: x = 4.1, y = 5.2
  integer :: i = 3
  character(5) :: greet = 'Hello'

contains
  subroutine foo()
    double precision :: z  ! New local variable

    print *, Greet

    z = x + y
    print *, z

    print *, i
  end subroutine
end module

上面,我使用了“新”::双冒号运算符,它允许一次声明和初始化多个变量。由于模块变量已经被save隐式 'd 了,这很好。

或者,如果这些模块是分开的,您也可以contains在主程序(或任何子程序)中设置部分并将子程序放在那里。优点是以这种方式声明的过程总是具有显式接口,这极大地有利于编译器的错误诊断,甚至在某些较新的情况下也需要。这是 F90 的主要改进之一,因为 F77 只处理外部子程序和隐式接口。

于 2013-01-10T17:24:51.620 回答
-1

执行公共块的最简单方法是每个公共块有一个包含文件,并在包含文件中进行所有声明。这样,公共块只在一个地方声明。必须将代码转换为使用模块的问题然后神奇地消失了。

此外,如果您正在开始新代码,则在公共块变量的名称前加上与命名公共块相同的名称将使编码更容易。最初这是一种痛苦,多年来一直在编码的主要女主角将拒绝遵守。维护代码的人会发现它很容易:没有 greps 或 groks。只看名字,你就知道它来自哪个公共块。

与模块保持相同的约定也有帮助。如果所有的例程名和变量名都以模块名开头,那么只要看名字就知道它来自哪个模块。

于 2013-03-17T09:15:34.780 回答