- 第一章 Fortran 语言程序设计初步
- 第二章 改变程序流程
- 第三章 循环结构
- 第四章 数据结构
- 第五章 数组
- 第六章 过程和模块
- 第七章 输入输出和文件
6.2.3 变元的性质
a) INTENT 属性
哑实结合是在两个程序单元间传递数值的主要手段,主程序中实元 2.0 与过程中哑元 X 结合,就使 X 有值 2.0,也即把主程序中 2.0 的值传递给子程序中的 X,该值可供子程序运算。反之,如果子程序中的变量 Y 在子程序执行完后有值 3.0,它与实元 R 结合后则使调用程序单元中的实元变量 R 得值 3.0。
在 F77 中,不能确切地说明哑元的目的。它们到底是用于把数据传入到过程中的,还是用于把数据传出到调用它的程序单元中的,或是两者兼而有之的,这个概念是含糊的。在 F90 中,为了避免当过程内部变量值变化后返回到引用的程序单元时可能造成的混淆情况,在过程的变量类型的定义中,可以对哑元指定意图说明的 INTENT 属性。哑元按数据传输特性可分为输入输出两用、仅用于输入和仅用于输出。其一般形式为:
在类型定义语句中:类型,INTENT(意图说明符) :: 哑元名表
或用 INTENT 语句 :INTENT(意图说明符) :: 哑元名表
意图说明符为以下字符串:
IN 指明哑元仅用于向过程提供数据,过程的执行期间哑元不能被重定义或成为未定义的,相联合的实元可以是常数、变量、数组以及它们的算术表达式。
OUT 指明哑元用于把过程中的数据传回调用过程的程序,与之相结合的实元只允许是变量,不得为常数或算术表达式。
INOUT 指明哑元既可以用于向过程提供数据,也可用于向调用程序返回数据,与之相结合的实元只允许是变量。
INTENT 属性不能在主程序说明语句中出现,只能在过程的哑元说明语句中使用。它是可选的,可省略。但现代特性的编程中应提倡使用 INTENT 属性,因为这样能增加可读性和可维护性,还能防止编程中的一些错误。因为一旦哑实结合,哑元和实元始终是同一个值,如果过程中给有属性 INTENT(IN) 的哑元重新赋值,也将改变调用程序单元中实元的值,而这是不应该的。这样,如在程序执行部分中误把有 INTENT(IN) 属性的哑元赋值时,操作系统就会提示。
例:给出 10 个步长的分布值,打印分布图形。 [e_623_01.f90]
b) SAVE 属性
在过程中变量的定义和取值当过程被调用结束后有可能变为不确定的,因此当过程再次被调用时,变量的取值在不同编译器下可能取值不同。为了避免这种情况的出现,在 F77 中可用 SAVE 语句,在 F90 中对变量增加了 SAVE 属性,其形式为:
在类型定义语句中:类型,SAVE, [其它属性] :: 变量名表
或用 SAVE 语句 :SAVE [变量名表]
在过程中设定初始值时要注意,类型定义中的初始值赋值法隐含了 SAVE 属性。 [e_623_02.f90]
c) 关键字变元
哑实结合必须遵循三个一致的原则,否则运行出错:哑元与实元位置一致;哑元与实元个数一致;哑元与实元类型一致。这就要求记住每个哑元的名及其位置,阅读实元表时对其中每个表达式要追溯到它原来的哑元是什么,非常不便,为此 F90 可以通过如下方法放宽这三个一致的原则:用关键字变元放宽位置一致;用可选择变元放宽个数一致;用类属过程放宽类型一致。
关键字变元是调用过程时变元的一种现代形式,它的写法是:哑元名=实元表达式。调用时,实元表中不仅要写出实元表达式,还要写出它对应的哑元变量名,这个哑元变量称为关键字,并用‘=’号与实元连接。使用关键字后,就不必记住哑元原来的次序,填写的实元次序可以任意。例如,对于子程序语句(对函数一样可用):
SUBROUTINE FACTORIAL(N,F_VALUE)
主调程序中,调用语句使用关键字变元时形式如下:
CALL FACTORIAL(N=M,F_VALUE=F_M)
CALL FACTORIAL(F_VALUE=F_M,N=M)
F90 也允许在调用语句中,前面部分实元不用关键字变元,只从某一个变元开始用关键字变元。此时,前面未使用关键字变元仍要保持与原来哑元次序相同,后面使用关键字变元的部分可以按任意次序排列。例如,对于
SUBROUTINE TEST(A,B,C,D)
调用时可以使用如下形式:
CALL TEST(1,10,100,1000)
CALL TEST(1,10,D=1000,C=100)
CALL TEST(D=1000,C=100,A=1,B=10)
但是,以下形式是错误的:
CALL TEST(10,1,C=100,D=1000) 头两个实元次序颠倒
CALL TEST(1,10,C=100,1000) 关键字变元后面都要写成关键字变元形式
主调程序中如采用关键字变元调用过程,就必须写出被调子程序的接口块。
d) 可选择变元与 OPTIONAL 属性
某些过程中,虽然哑元表中列出好几个哑元,但在实际调用时不一定每次都全部用到。这种情况下,F90 允许只对哑元表中部分哑元作哑实结合,另一部分哑元则按需要可选择结合,称为选择变元。例如内在数组函数 SUM,它的完整的函数及哑元表为 SUM(ARRAY,DIM,MASK),其中,后二个哑元 DIM、MASK 就是可选择变元。主调程序调用时,可以不选后两个变元,只对第一个变元作哑实结合,如 SUM(A);也可选上第二个哑元,如 SUM(A,DIM=2);或后两个可选变元都选中,如 SUM(A,DIM=2,MASK=A>0)。
编写有可选择变元的过程时,可选择变元必须说明具有 OPTIONAL 属性,并要使用 PRESET 内在函数。一个哑元是否为可选哑元,看它是否有 OPTIONAL 属性,有 OPTIONAL 属性的哑元是可选变元,没有 OPTIONAL 属性的哑元是必选的。内在函数 PRESET 用来反映它的自变量是否在程序执行部分中出现。PRESET(A) 的值是一个逻辑值,当 A 出现(被使用到)时,函数值为真,否则为假。利用 PRESET 函数的真假值,可以通过 IF 构造作出变元是否出现时的不同算法。
例如,要求编一子程序,既能求四边形同长(A+B+C+D) 的值,也能求三角形周长(A+B+C) 的值。此时 D 就是可选择变元,并规定当 D 不出现时,置 D 值为零。子程序如下:
SUBROUTINE SUM(S,A,B,C,D)
IMPLICIT NONE
REAL,INTENT(IN) :: A,B,C
REAL,INTENT(IN),OPTIONAL :: D
REAL,INTENT(OUT) :: S
REAL :: TEMP
IF(PRESET(D)) THEN
TEMP=D
ELSE
TEMP=0.
END IF
S=A+B+C+TEMP
END SUBROUTINE SUM
e) 哑元改名
过程的优点是具有广泛通用性,一旦编好,解各种问题的主程序都可调用它。但是在为不同目的而使用时,具体问题的物理名称不同。为了加强可读性与可维护性,在不同领域使用过程时,需把哑元名称改为与该领域中的物理名称一致,而 F90 允许改变变元名称。名称的改变是在接口块中进行的,所以主调程序中要写出接口块。
例如,对于上面求边长的子程序,如调用时欲把哑元名 A,B,C,D 改为物理意义明确的名称 UPPER,DOWN,LEFT,RIGHT,只需在主调程序中写入接口块,在接口块的哑元表中用新的哑元名即可:
PROGRAM SUMMATION
INTERFACE
SUBROUTINE SUM(S,UPPER,DOWN,LEFT,RIGHT)
IMPLICIT NONE
REAL,INTENT(IN) :: UPPER,DOWN,LEFT
REAL,INTENT(IN),OPTIONAL :: RIGHT
REAL,INTENT(OUT) :: S
REAL :: TEMP
END SUBROUTINE SUM
END INTERFACE
READ *, UPPER,DOWN,LEFT,RIGHT
CALL SUBROUTINE SUM(S,UPPER,DOWN,LEFT,RIGHT)
……
END PROGRAM SUMMATION
f) INTRINSIC 属性
与 EXTERNAL 语句或属性说明的实元是外部过程相对应,INTRINSIC 语句或属性用来说明实元实际上是内在过程。其一般形式为:
类型定义语句:类型,INTRINSIC :: 内在函数名[,内在函数名]…
或 INTRINSIC 语句:INTRINSIC 内在过程名[,内在过程名]…
内在过程名必须是内在过程的通用名或专用名。如果是专用名,则可以在其作用范围单元中作为一个过程的实元,但它必须出现在一个 INTRINSIC 语句中,或被该单元中的一个类型声明语句指明具有 INTRINSIC 属性。需要注意的是,一个内在过程名只能在 INTRINSIC 语句中出现一次,并且不能同时出现在 INTRINSIC 语句和 EXTERNAL 语句中。
例:PROGRAM MAIN
REAL F
REAL,INTRINSIC :: ALOG
F=CALCULATE(0.,1.,ALOG) !使用内在函数 ALOG 作实元
…
END PROGRAM
注意这里必须用专用名 ALOG,而不能用通用名 LOG。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论