FORTRAN 90 程序编程规范.docx
《FORTRAN 90 程序编程规范.docx》由会员分享,可在线阅读,更多相关《FORTRAN 90 程序编程规范.docx(11页珍藏版)》请在冰豆网上搜索。
FORTRAN90程序编程规范
FORTRAN90程序编程规范
Fortran90编程规范,使程序代码高度组织化,更加易读、易懂、易于维护,程序更加高效。
使编出的程序更易懂、易于维护。
1语言选择
数值预报创新系统软件开发应避免使用Fortran77的某些过时特征以Fortran90不一致的特征。
选择Fortran90作为开发语言,并采用Fortran90的新功能,如动态内存的分配(dynamicmemoryallocation)、递归(recursion),模块(modules)、POINTER、长变量名、自由格式等。
Fortran77其中某些只是一些冗余的功能,这些功能已经过时,另外,还有一些在Fortran90中被证明是不好的用法,建议不要使用。
2Fortran90的新特性
2.1.1建议使用的Fortran90新特性
建议使用Fortran90提供的模块(module),并用UseONLY指定module中哪些变量或派生类型定义可用于调用程序。
尽量使用数组下标三元组,这样可优化并减少所需的代码行数。
为提高可读性,要在括号内表明数组的维数,例如:
1dArrayA(:
)=1dArrayB(:
)+1dArrayC(:
)
2dArray(:
:
)=scalar*Another2dArray(:
:
)
当访问数组的子集时,例如在有限差分等式中,可以通过使用下标三元组实现。
例如:
2dArray(:
2:
len2)=scalar*(&
Another2dArray(:
1:
len2-1)&
-Another2dArray(:
2:
len2)&
)
对程序单元(programunits)命名,并使用Endprogram,Endsubroutine,Endinterface,Endmodule等结构再次指定“programunit”的名称。
在逻辑表达式中使用>、>=、==、<、<=、/=,它们分别代替.gt.、.ge.、.eq.、.lt.、.le.、.ne.。
新的表示方法更接近标准的数学符号
在变量定义中始终使用“:
:
”;始终用“DIMENSION”定义数组形状;始终用(len=)的语法格式声明字符变量的长度。
从效率的角度考虑,除递归定义的数据结构外,应尽量避免使用递归程序(它在使用内存和cpu上会降低效率)。
建议定义新的操作符,而不要重载已有的操作符,这样可以清晰地表明功能,避免降低代码的可读性和可维护性。
2.1.2关于Interface
使用Interface接口块。
在FORTRAN语言中,主调程序与被调程序是分别编译的。
由于Fortran90对过程的许多功能做了扩充,有些功能单靠简单的调用语句已无法反映,因而系统也就无法进行正确的编译。
这时需要在主调程序中加入interface接口块,通过它为主调程序与被调程序指明一个显式的接口。
如果被调用程序中哑元含有假定形状(assumed-shape)数组,或含可选变元,或含键盘输入的参数,就需要interface接口块说明。
一般来讲,在Fortran90程序之间需要提供的interface块,建议将interface接口块明确写入调用程序,并复制被调用程序的参数列表。
这种方法简单易用,但也相应增加了维护代码的工作量,因为只要被调用程序的参数列表发生变化就必须相应改变interface接口块和调用(call)语句。
2.1.3关于动态内存的使用
并行程序中存在着动态内存使用不充分的情况,合理使用动态内存可提高效率。
在Fortran90中常采用下列方法获取动态内存。
自动数组(automaticarrays):
这种数组的大小在子程序中指定,其大小取决于运行时的变量,例如,可通过参数列表向子程序传递实元变量。
使用自动数组优先于其它形式的动态内存分配方法。
可分配数组(allocatablearrays):
声明为ALLOCATABLE属性的数组变量可在运行时通过ALLOCATE命令分配空间。
与指针不同的是ALLOCATABLE属性不能用于派生数据类型中。
这种方法申请的空间要使用DEALLOCATE命令释放。
在一个程序中,不要重复进行“ALLOCATE—DEALLOCATE-然后再ALLOCATE一个更大的空间”这样的操作,这样会导致大量不可利用的碎片空间产生。
应在程序中对要开辟的动态数组空间进行连续分配,或连续释放。
在使用ALLOCATE和DEALLOCATE命令之后,要利用ALLOCATE和DEALLOCATE命令参数中的返回值来判断操作是否成功;不建议使用指针数组。
2.2Fortran90中不建议使用的过时的特性
不要使用固定书写格式,采用Fortran90的自由书写格式。
不要使用旧式的DO循环和CONTINUE语句。
在以前的DO循环中,关键字之后大多有一个标号,循环在该标号处结束,如:
DO10I=1,10
DO20j=1,20
A(i,j)=0.
20CONTINUE˜
10CONTINUE˜
建议采用统一的DO结构,如:
DOi=1,10
DOj=1,20
A(i,j)=0.
ENDDO
ENDDO
不能使用实循环变量˜
在DO循环中若用实数作循环变量,由于截断误差的存在,会导致得不到预期的循环次数,如应将下面的DO循环
DOr=0.1,0.9,0.1
...
ENDDO
改写为:
DOi=1,9
r=i*0.1
...
ENDDO
不要使用DOWHILE语句,可用不带循环变量的DO语句配合exit替代,如:
不要使用选择性返回。
例如:
CALLFoo(x,y,*100,*200,*300)
在执行完该子程序后程序根据Foo的返回语句后的表达式值选择从标号为100、200、
300处继续执行。
可将上述子程改写为结构化CASE语句:
CALLFoo(x,y,return_code)
SELECTCASE(return_code)
...
不要使用算法IF语句:
使用块IF结构来代替;
不要使用计算GOTO语句,如GOTO(10,20,30)i;
不要使用标号赋值语句,如
ASSIGN300i
GOTOi
不要使用除IMPLICITNONE之外的任何implicit语句,如
IMPLICITREAL(a-z)
不要使用DATA语句,对变量赋初值可在声明时进行,或在程序中进行。
DATA语句是唯一可用于对变量赋二进制、八进制、十六进制初值的语句,但它很可能
造成程序的不可移植,因此除非必须这样做,一般建议不要采用。
不要使用COMMON公共块:
使用Modules参数列表代替公共块向子程序传递数据;
不要使用EQUIVALENCE等价语句:
Fortran90中,由于模块、动态存储、指针、数据结构以及固有函数transfer的引用,没有必要继续使用EQUIVALENCE语句;
不要使用数据块程序单元DATABLOCK,在FORTRAN77中它用于给公用块内数据赋初值。
不要使用FORMAT语句。
不要使用err=,end=及eor=等描述符。
在输入输出语句中,这些描述符后面跟语句标号,指示如果出现错误则程序转向执行标号所标识的语句。
我们可用检查iostat来替代,如:
READ(*,”(A)”,iostat=status)line
不要使用语句函数,如
f(x)=x**2-1
可用contain内部函数子程序来代替。
不要使用假定大小数组
它是作为哑元使用的,它的最后一维无上界,而用*代替,如
DIMENSIONa(100,*)。
在Fortran90中可用假定形状数组代替,它的每一维都是可调的,并用(:
)来声明,
如:
REAL,DIMENSION(100,:
):
:
a
不要使用FORTRAN的INCLUDE行。
在多数情况下可用USE来代替,有些则采用预处
理#include来代替。
不能使用双精度类型,采用Fortran90的种别参数。
不要使用PAUSE语句;
不要使用ENTRY语句:
一个子程序只能有一个入口点;Fortran90中避免数组在子程序之间传递时维数的隐式改变。
尽量不要采用经销商扩充的功能。
2.3在FORTRAN90中限制使用的功能
GOTO语句和语句标号只能在程序出现异常情况需要立即退出时才能使用,即允许使用GOTO语句的唯一例外,是在出现错误时跳到程序的末尾处,这时用9999作为Labels
(这样可使所有人都知道GOTO9999的意思)。
2.4关于预编译器(Precompilers)的使用
建议在数值预报创新系统中使用预编译器,因为它提供了一种可有选择的对程序系统的某一部分程序进行编译的方法(条件编译);另外,为了提高程序的可移植性,同样也需要使用预编译器。
由于超级计算机都是用UNIX操作系统,C预编译器(cpp,Clanguagepre-processor)可能是最好的选择。
2.4.1文件的包含
Fortran90提供了利用“INCLUDE”语句引入文件的功能,但有时需要加入文件的目录结构信息,因此可以改用cpp中的#include功能,是程序更加清晰。
“include”后的文件可以是用于变量定义、子程序注释或interface接口块等的一段程序。
如,
SUBROUTINEFoo
IMPLICITNONE
...
INTERFACE
#include
#include
#include
...
CALLTypePackageIni
#endif
...
ENDSUBROUTINEFoo
将视type_package_init的定义调用子程序TypePackageIni。
3可读性与可维护性
本节将主要介绍如何使Fortran90程序更易读、更易维护。
3.1空白的使用
空白的使用可以使程序更易读、易维护。
加入空白的方法主要有空行、空格。
3.1.1空行
在程序“段落”之间加入空行,可以使程序的逻辑结构更加清楚,程序段落更加明白。
如
PROGRAMFoo
USEmodule_a
USEmodule_b
IMPLICITENONE
REAL:
:
time
REAl:
:
value
INTEGERloop
value=3.1415926
WRITE(*,*)value
ENDPROGRAMFoo
3.1.2空格
在一行中加入一些空格,可以使程序更易读,如在赋值号左右至少加一个空格,在逗号后加一个空格。
!
Initializevariables
X=1
MeaningfulName=3
RealNumber=5
可改写为:
!
Initializevariables
X=1
MeaningfulName=3
RealNumber=5
3.1.3缩进
为了能够更加清楚的显示程序的逻辑结构,我们采用四格缩进的方法,即在上一行开始处空三格在第四格开始书写。
例如下面是IF语句块的一个示例:
!
ExampleIfblock
IF(...)THEN
!
acomment
DOLoop=1,EndLoop
!
anothercomment
...codestatements...
ENDDO
ELESIF(...)THEN
!
anothercomment
......codestatements......
ENDIF
3.2程序文档及注释
程序文档和注释可以帮助读者了解仅看程序不易或无法了解的信息,这有几个层次:
程序外应有科学文档、程序文档及用户指南等软件文档。
在程序头应有程序头文件在程序中应有段落注释及行注释。
3.2.1软件文档
软件工程中除了要编写工程文档外,还要编写软件文档,这是软件工程必不可少的部分。
多数情况下,程序软件文档提供软件包级的文档,而不是单个程序的文档,它包括:
科学文档:
陈述软件包拟解决的问题以及采用方法的基本原理。
该文档与代码本身无关。
程序文档:
说明在科学文档中描述的方法的实现。
所有软件包中的程序都要列出并作简短的功能说明,并列出软件包中各程序的调用关系树(或流程图)。
用户指南:
详细描述软件包的输入输出参数和文件。
这包括软件包内程序的参数、开关值、可调参数的取值范围,要说明缺省值和敏感值的范围。
要对读入的文件和namelist有详细的说明。
3.2.2程序头文件
每个程序都要有头文件,一般放在程序开头,内容包括本程序模块的功能和目的说明、模块的接口说明(如调用实例、参数描述和子模块清单等)、有关数据的说明(如重要的变量及其用途、约束和限制条件,以及其它有关信息)、开发历史记录(包括模块设计与编程人员名单、复审人员及复审日期、修改日期和有关说明等);头文件还描述程序的函数、引用的外部文档和程序使用的变量,程序中使用的变量都要在头文件中声明并注明用途。
附录A给出了程序头文件的标准模板。
文件头的写法将在第六章中详细讨论。
3.2.3程序注释
程序内部的注释说明本段或本行程序代码的含义或要进行的操作。
片段注释:
把代码分成一些逻辑片段,注释放在定义片段开始的部分,它嵌在程序体内用以描述处理功能,如在函数/子程序/过程语句调用前后,循环语句前后以及重要语句旁边都要加上注释语句。
片段注释的目的是说明代码某一部分的功能,它应当放在要注释的代码行上,或者放在要注释的代码行的前一行。
注释应当顺序编号,如使用1.0,2.0等:
!
---------------------------------------------˜
!
<片段号><片段标题>
!
---------------------------------------------˜
建议:
软件文档使用中文编写,并提供相应的英文摘要;程序头和注释全部使用英文编写。
3.3有意义的名称
给文件、子程序、常量、变量一个有意义的名称。
一般的做法是用相应的英文或缩写、习惯名称命名。
选择一个有意义的名称,在程序中始终不变;
当需要缩写时,采用统一的方法,如当给一组与“Datarefresher”有关的函数命名时,可用dr_规定;
缩写应避免误解,如不要用inch表示inputchar,可用in_char表示;
用下划线使名称更易读;
可使用长变量名增加可读性,但是不宜过长;
各名称之间必须使用有两个或以上的字符不相同,以免混淆,如systet与systest;
不要用大小写来区分变量;
导出类型的名、模块名、子程序名、函数等不能与变量名同名。
虽然有些Fortran是
允许的,但是为了避免混淆,我们规定不许同名。
3.3.1标准名称
以下列出了一些标准的短变量的习惯命名法:
ccharacters
i,j,k下标
n计数器
p,q指针
s字符串
3.3.2名称的大小写
虽然Fortran不区分大小写(字符型除外),为了更加容易区分各种名称,我们规定各种名称书写的大小写规范,但是在使用通常的习惯用法给变量命名时,不受这个限制。
变量名用小写,字与字之间加下划线,但气象上某些有特别含义的变量用法除外,如:
T表示温度等
子程序、函数名第一个字母用大写,不用下划线,如:
CreatDomain
常量全部用大写,字之间可用下划线
模块名全部用小写,字之间用下划线,并以前缀module_开头
派生类型名全部用小写,字之间用下划线,并以前缀type_开头。
4.建议采用cvs管理程序
CVS首先是一个版本管理系统,它可以保留软件开发过程中的每一个版本的信息,包括谁、在何时、作了什么样的修改以及为什么作这样的修改等。
它的最大的特点是它的并发性,即它支持分布式项目的开发。
一个程序员开发出了自己负责模块的新版本后,迅速的通过CVS让开发组的每一个成员都分享自己的最新成果。
甚至,CVS通过特定的机制允许多个程序员同时修改同一个源程序文件。