目前在我的程序中,我有几个共同的块分布在几个子程序和函数中。当我向其添加变量时,我有时会忘记更改公共块的所有实例。我想将这些公共块放到模块中,这样我就可以在一个地方添加和删除模块中的变量,而不必担心在子程序中更新模块的所有实例。
我是否需要在程序中包含'use'语句来初始化模块中的变量,或者我是否将程序包含在模块中?我通常会使用公共块,但我正在尝试实现模块,因为我认为它们将帮助我的代码在复杂性增加时保持可读性。
注意:模块中的某些变量值需要能够在从一个程序传递到另一个程序时进行更改。
我尝试编写一个简化的测试程序,以熟悉模块但无法使其工作。我熟悉fortran 77,但之前从未使用过模块。我感谢任何帮助或建议。
我正在使用gfortran 4.6.1
Main.f
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
答案 0 :(得分:4)
您只需要一个模块实例。您将其与use
语句一起使用的任何主程序或过程(子例程或函数)都知道。如果你有一个设置值的子程序,那么就像任何其他子程序一样,它必须有一个use
语句。如果要设置初始值,您可以在声明中这样做。如果主程序使用该模块,则它将始终在范围内,并且变量的值将在整个程序运行期间保持不变。如果模块仅由过程使用,原则上,当这些过程都不在调用链中并且允许编译器忘记模块变量的值时,模块将超出范围。 (值得怀疑的是,任何Fortran编译器实际上都是这样做的。)这可以通过用SAVE
声明每个变量来防止。如果您使用初始值声明变量,则SAVE
是隐式的。
通常,在使用模块之前必须先编译模块,以便编译器在遇到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
答案 1 :(得分:1)
您的代码无法编译的原因有几个:
您的模块位于主程序之后,这意味着它们在您use
之前就不会被编译。将它们放在单独的文件中并在主程序之前编译它们,或者将它们放在主程序之前。
您在主程序中重新声明模块中的变量,编译器将其解释为名称冲突。具有public
属性(默认值)的所有模块变量将在您use
模块的范围内可用;这被称为“使用关联”。换句话说,use vals
足以让x
,y
和int
可用。
此外,模块更像是单例对象而不仅仅是数据容器。它们还可以包含在contains
语句之后列出的过程,这有助于将变量和相关过程分组在一起。一个例子是将两个模块分为一个,以及子例程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
上面,我使用了“new”::
双冒号运算符,它允许一次声明和初始化多个变量。由于模块变量已经隐式save
,所以这很好。
或者,如果要将这些模块分开,您还可以在主程序(或任何子程序)中包含contains
个部分,并将子程序放在那里。优点是以这种方式声明的过程总是具有显式接口,这极大地有利于编译器的错误诊断,甚至在某些较新的情况下也是必需的。这是F90的主要改进之一,因为F77只处理外部子程序和隐式接口。
答案 2 :(得分:-1)
执行公共块的最简单方法是为每个公共块提供一个包含文件,并在包含文件中进行所有声明。这样,公共块只在一个地方声明。必须将代码转换为使用模块然后神奇地消失的问题。
此外,如果您要开始使用新代码,那么使用与命名公共块相同名称的公共块变量的名称前缀将使编码更容易。最初这是一种痛苦,多年来一直编码的主要人员将拒绝遵守。维护代码的人会发现它很容易:没有greps或groks。只需查看名称,就可以知道它来自哪个常见块。
与模块保持相同的约定也有帮助。如果所有例程名称和变量名称都以模块名称开头,那么只需查看名称,就可以知道它来自哪个模块。