Fortran中不能定义全局变量,但是可以通过一些方式在主程序和函数之间实现变量的共享,这个可以通过两种方式完成,模块module和公共区common。
module
模块的结构如下:
1 2 3 4 5
| module 模块名 模块中的变量 contains 模块中的函数 end module 模块名
|
模块其实就是包含一些变量和函数的一个集合。只要模块中的变量都有save属性,则可以通过module实现数据的共享。gfortran中module里的变量默认就是save的。编译完含module的源代码之后,目录下会出现以module为名字的.mod文件,运行编译完成的二进制文件的时候,这些mod文件是不能删掉的。
例如我想共享常数pi的值和add函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| 1 module const 2 implicit none 3 real, parameter :: pi=3.1415927 4 contains 5 real function add(x, y) 6 implicit none 7 real :: x, y 8 add = x + y 9 end function add 10 end module const 11 program main 12 use const 13 implicit none 14 write(*,*) add(1.0,2.0)*pi 15 end program main
|
上述const模块中包含了一个pi变量和一个add函数。use这个模块后方可访问module中的元素,注意这里use需要放在定义变量之前。
module中的元素也有公有和私有之分,类似C++中”class”里的内容(Fortran中也有class关键字,但是完全不是一个东西,C++中class和struct对应Fortran中的type关键字)。公有的变量在模块内或者use这个模块的程序块中都可以访问。私有的变量只有在模块内部进行访问。例如一个根据半径求面积和周长的函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| 1 module circle 2 implicit none 3 private 4 public :: area, length 5 real, parameter :: pi=3.1415927 6 contains 7 real function area(r) 8 implicit none 9 real :: r 10 area = pi*r**2 11 end function area 12 real function length 13 implicit none 14 real :: r 15 length = 2*pi*r 16 end function length 17 end module circle 18 program main 19 use circle, only: area 20 implicit none 21 write(*,*) area(2.0) 22 end program main
|
若要实现module中成员的公有化或私有化,可以在定义变量之前加上public或private。则该模块内所有成员都会默认公有或者私有。例如上述代码中所加private关键字就会导致pi变量在program中无法访问。在公有环境中若要定义私有成员,则另行声明即可。例如area和length函数的公有化声明。若在私有环境中定义公有,则也是类似方式完成。use一个module的时候,若仅想访问其中的一些成员的时候,可以用only关键字列出期望访问的成员即可。注意这里的function不需要另行声明external。
关于module的内容有很多,module是Fortran90标准之后的一个精髓,熟悉之后会减少很多不必要的工作,其他用法以后还会提及。
common
common充斥在老代码中,用于共享变量,它是通过内存对齐的方式访问的,例如共享数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 1 program main 2 implicit none 3 real :: vec1(5), vec2(5) 4 common vec1, vec2 5 call init() 6 write(*,*) vec1, vec2 7 end program main 8 subroutine init() 9 implicit none 10 real :: vec1(5), vec2(5) 11 common vec1, vec2 12 vec1 = 1 13 vec2 = 2 14 end subroutine init
|
在子程序init中要对变量vec1和vec2进行赋值,则在变量定义完之后利用common关键字进行共享声明即可,但是这里有个问题就是当变量多的时候,若元素没有一一对应,编译的时候这里并不会报错,这样的问题很难查找出来。而且若你仅想共享vec2变量,这里也需要把vec1变量写出来,使得引用变得非常麻烦。module中就不存在这样的问题。另外common的变量还可以分组和利用block data进行赋初值。例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| 1 block data init 2 implicit none 3 real :: r1, r2 4 integer :: i1, i2 5 common /intt/ i1, i2 6 common /reall/ r1, r2 7 data i1,i2,r1,r2 /1,2,1.0,2.0/ 8 end block data init 9 program main 10 implicit none 11 real :: r1, r2 12 integer :: i1, i2 13 common /intt/ i1, i2 14 common /reall/ r1, r2 15 write(*,*) i1,i2,r1,r2 16 end program main
|
在block data中只能使用data进行赋值。这里强烈建议放弃使用common相关语法。当代码量比较大的时候,很容易出现一些很难调试的运行时错误。