首页 > 教程 > 正文

阅读排行

FAQ 之 common,Module共享数据的优缺点
2015-01-23 21:30:52   来源:Fcode研讨团队   评论:4 点击:

本文介绍了common及Module两种共享数据的方式,其差异及优缺点对比。希望读者都能采用module共享内存,而摒弃common老语法。

在较老的 FORTRAN 代码中,经常看到 common 语句。(它的官方名字叫 公共区,而不叫全局变量

然而,这个历史上的语句却具有非常多的缺陷:
1. 它只说明变量具有在公共区的属性,并不说明变量的类型和精度。
2. 公共区采用内存字节一一对应,而不是采用变量名称一一对应。这极易发生错误,且难以排查和调试。

因此,我们强烈建议,在新书写的代码里,避免使用 COMMON 语句,而使用 Module 语句代替它。

一. COMMON 的弊病

下面我们来看一个例子,如下代码:
01program www_fcode_cn
02  Implicit None
03  common a ,
04  Integer :: a = 1 , b = 2 !// common 并不说明类型,需单独定义类型
05  call SubOK()
06  call SubOrder()
07  call SubType()
08  call SubKind()
09End Program www_fcode_cn
10 
11Subroutine SubOK()
12  Implicit None
13  common a , b
14  Integer :: a , b
15  write(*,*) a , b !// 输出1,2,正确
16End Subroutine SubOK
17 
18Subroutine SubOrder()
19  Implicit None
20  common b , a !// common 按顺序对应
21  Integer :: a , b
22  write(*,*) a , b !// 输出 2,1 颠倒
23End Subroutine SubOrder
24 
25Subroutine SubType()
26  Implicit None
27  common a , b
28  real :: a , b !// 类型不一致
29  write(*,*) a , b
30  !// 输出 1.40129846E-45   2.80259693E-45 完全错误
31End Subroutine SubType
32 
33Subroutine SubKind()
34  Implicit None
35  common a , b
36  Integer(Kind=8) :: a , b !// Kind 不一致
37  write(*,*) a , b
38  !// 输出 8589934593  0 完全错误
39End Subroutine SubKind
我们看到,主程序中书写了 common 语句,其中有两个变量 a 和 b。但由于 common 并不说明变量的类型和精度,因此我们需要单独定义它们,使用语句: integer a , b

如果没有显式定义,也没有 Implicit None 语句,那么按照 IN 规则,以 a b 开头的变量,为 real 类型(我们同样强烈建议您书写 Implicit None,而不要省略它)

我们分别在4个子程序中使用了 common 公共区的数据。但只有 SubOK 中是正确的,它必须具有相同的变量顺序,变量类型,变量精度(Kind值)。

在 SubOrder 中,a 和 b 的顺序写反了。这就导致值也不正确了。

而在 SubType 中,a 和 b 被定义成了 real 类型。这样的结果更糟糕,完全面目全非。

即便是 Integer 类型,Kind值不同,也会影响 common 的正确对应。如 SubKind 函数中的演示。

同时,common 公共区的变量,需要在每一个使用它的函数内重新定义,且必须保证对应变量的顺序、精度、大小、长度等完全一致。稍有差别就会出现对应“错位”

因此,在实际工作中,common 的使用,加上没有 Implicit None 而出现的 IN 规则,若干变量未定义,或变量的精度不确定。就非常容易发生错误。

二. Module 共享数据的方便、可靠

Module 是 Fortran90 引入的一个重要概念。关于它的内容比较多,在此仅简单介绍它的一小部分内容(用于数据的共享)。

一个 Module 是一个代码单元,与主程序,外部子(例行)程序或函数是差不多的“等级”。但它的功能更强大,也更便捷。

在 Module 中,我们可以定义若干变量(含数组、type、可分配数组等) 。这些变量会存储在一个特定的空间内,而被所有 use 了该模块的程序单元直接使用。而且这种使用,是按照变量的名称而对应的,而非变量的内存字节顺序。

同时,use 了该模块的程序单元,也继承了这些变量的类型、精度、大小、长度等属性,而不必(也不能)重新定义。

01Module modname
02  Implicit None
03  !// 明确变量类型,顺序无关
04  Integer , save :: a = 1 , b = 2 
05End Module modname
06 
07program www_fcode_cn
08  use modname !// 无需,也不能再定义 a b
09  Implicit None
10  write(*,*) b , a !// 输出 2,1 正确
11  a = 3
12  b = 4
13  !// 按变量名对应,因此倒序输出,其值也倒序
14  call Sub()
15End Program www_fcode_cn
16 
17Subroutine Sub()
18  use modname !// 无需,也不能再定义 a b
19  Implicit None
20  write(*,*) a , b !// 输出 3,4 正确
21End Subroutine Sub
在这段代码中,我们书写了一个 Module,名叫 modname。其中包含两个变量 a b,并含有初值 1 和 2

save 属性表明这些变量会被保存起来,以便在不同的程序单元间保持同样的值。
(虽然语法未明确指出,但所有的编译器都默许 Module 中的变量具有 save 属性,因此,很多时候 save 也可以忽略不写)

在主程序和子程序 Sub 中,我们的 use modname 语句,表示这两个程序单元都使用了 modname 这个模块。

由于使用了这个模块,在主程序和 sub 中,可以直接访问 a b 两个变量,而无需(也不能)再次声明他们。

在主程序里,我们的 a b 输出顺序颠倒了。但可以看到,输出的结果是符合我们预期的。

同时,在主程序中改变 a b 的值,同样会影响 sub 子程序中对应的 a b 的值。实现了数据的共享。

由于 Module 内变量的方便使用、共享,同时根据名称来对应也不容易出错。无需再次声明也不会出现精度变量的不一致。综合这些优点,Module 可完全替代,更应该替代 COMMON。

除此之外,Module 还可以封装若干子程序(或函数),对变量设置私有(private)或保护(Protect)属性,对具有特殊用途的变量进行权限的分级。

如果读者有兴趣,可以从较新的教材(书名里的 Fortran 为小写字母)里找到更多的 Module 的介绍,您会发现,Module 是一个广阔神奇的新世界。

相关热词搜索:common module

上一篇:Fortran流文件-读写二进制任意位置
下一篇:Intel Visual Fortran OpenGL 初步

分享到:           收藏