什么是过程
Fortran编译系统提供内在函数,可以在任意程序单元中引用。但是在许多时候仅仅使用系统的内在函数并不能满足程序设计的需要,因此就需要自行编制相应的函数或子程序来扩充程序的处理能力。
过程是在程序的执行中可被直接调用的、封装在一起的、进行计算或处理的语句序列。它是任何一种过程型程序设计语言的重要组成部分,对
Fortran语言也不例外。F90中,一个过程的定义就是指它是一个函数或是一个子程序。
过程的引用就是调用一个过程。建立过程的目的就是建立可多次重复执行的程序段,以便多次调用它们。通常过程是带有参数的,在
Fortran中把参数称为变元(实元或哑元),过程定义中的变元
是哑元
,过程引用中的变元是实元。在调用过程时,要用实元
代替哑元
,这
就是哑实结合
。
过程包括下面几种类型:
外部过程
:它是在某个外部程序单元中定义的独立过程,或是用非
Fortran语言编写的过程。
内部过程
:在程序单元内部定义而且只能被该程序单元调用。
内在过程
:由编译系统内部定义,不用任何附加声明或说明就可以可直接引用。
模块过程
:它在模块中定义,可以被所有使用该模块的程序调用。包含过程的模块称为宿主。
哑
过程
:如果
一个哑元被
指明为过程或作为过程名出现在过程引用中,那么该哑元代表的过程为一个
哑
过程。
语句函数
:它是由单个语句定义的函数,其形式为:
函数名
([
哑元名表
])=标量表达式
。
F90不推荐使用,因为它不符合过程的一般规则。
过程的特性包括,将过程分为函数和子程序的分类特性和它
的哑元的
特性,对于函数还包括有结果的特性。
一个
哑元可以
是一个虚拟数据对象、
哑过程
或作为选择返回
指示符的星号
。当一个
哑元不是
星号时,它可有
OPTIONAL属性,表示对该过程引用时不需要有实元与该
哑元结合
。一个
哑
元数据对象的主要特性包括它的类型、种别值、形状、输入输出意向(INTENT)、是否可选(OPTIONAL)、是否一个指针(POINTER)或目标(TARGET)。
哑
过程的特性包括其接口是否显式给出、作为过程的特性(如果其接口显式给出)以及它是否可选。函数结果的主要特性包括它的类型、类别值、
秩
以及是否指针等。
6.2.2
外部过程
外部过程是程序员编写的函数或子程序,它独立于主程序外部。外部过程可以单独以源文件存储和编译,也可以包括在主程序源代码的
END语句后。外部过程本身也可以包含有内部函数或内部子程序。
子程序以
SUBROURTINE语句开始,END语句结束的过程。其一般形式为:
[前缀]
SUBROUTINE
子程序
名
[(
哑元列表
)]
END [SUBROUTINE[子程序名]]
其中,
哑元可以
是变量名、数组名、过程名、
指针名等均
可
作为哑元
。
哑元表内
列出本程序体内要用到的
全部哑元
,列在括号内,彼此用逗号分隔(哑元都要在说明语句中说明类型)。
前缀
是
F90中新增的,它可以是:
类型说明 [关键词]
或
关键词 [类型说明]
。
关键词
是下面之一:
RECURSIVE
(F90),
PURE
(F95),
ELEMENTAL
(F95)。RECURSIVE表示过程时可以直接或间接地调用自身,即递归调用,其过程是递归过程。
子程序
名只是
用
来作
标识,不代表任何值。
哑元列表
是子程序与调用单元之间进行数据传送的主要渠道,当有一个
以上哑元时
,它们之间用逗号隔开,如果
没有哑元
,则一对括号可以省略。从
SUBROUTINE语句后面一直到END语句则是子程序体。它的说明部分应包括对哑元和子程序中所用变量、数组等的说明,它的执行语句部分完成运算和操作功能。其中的END语句或RETURN语句使执行流程返回到调用单元。
哑元表中的哑元个数
,理论上不受限制,但从软件工程观点看,不宜过多,一般不应超过六、七个。如果太多,意味着该子程序的算法较复杂,应该把该过程再分解为几个子功能分别编写成几个子程序。
调用子程序时必须用一条独立的
CALL语句,其形式为:
CALL子程序名[(实元列表)]
例:读入
3个整数,按大小順序重排。
INTEGER :
:
i,j,k
READ *,
i
,j,k
IF(
i
<j) CALL swap(
i,j
)
IF(
j<k) CALL
swap(
j,k
)
IF(
i
<j) CALL swap(
i,j
)
PRINT *
,
i,j,k
SUBROUTINE
swap(
p,q
)
INTEGER :
:
p,q,r
r=
p
;p
=
q;q
=r
RETURN
调用子程序时的实元是
和哑元相同
类型的变量、数组元素、数组和常数。当用
CALL语句予以调用时,哑元和实元才按列表顺序一一对应,取得同一数值。但使用常数时要避免下例中的常数替换式,否则将导致不可预料的错误,应尽可能用变量作实元。
例:
SUBROUTINE
bai
(x)
REAL :
: x
x = 2. *
x
CALL
bai
(
1.)
PRINT*
,s
自定义函数和子程序比较相近,共同的特征是作为过程的集合,子程序的很多规则也可应用。两者的不同之处在于函数返回一个值,且通常不
改变哑元的
值,因此,它代表数学上的一个函数。而子程序通常完成一项更为复杂的任务,通过变元或其他手段返回几个结果。函数的一般形式为:
[前缀] FUNCTION函数
名
([
哑元列表
])
[RESULT(结果名)]
END [FUNCTION函数
名
]
如果
没有哑元
,则
哑元表
是一个空括号。
RESULT是关键字,要照写,后面括号内的变量名就是函数计算的结果值。函数结果变量名有值,必须在说明语句中说明类型,在程序执行部分中至少赋值一次。在引用时,它的
值就是
函数值。函数结果
名不可列入哑元表
。如果没有结果名,则函数名就是结果名。F90中之所以增添了结果
名功能
,就是为了区别函数字面上的名称(函数名)和实际运算结果变量的名称。
函数调用与调用内在函数形式一样,在主调程序任何处,作为表达式的一项写下:
函数名
(实元表)
就完成调用。如果函数
无哑元
,则调用形式是在表达式中写上函数名,后跟空括号:函数名
()。系统在该位置上返回以该实元为自变量的函数结果值,参加表达式的运算。
例如,下面都是合法的
FUNCTION语句:
FUNCTION FUN1
FUNCTION
FUN2()
INTEGER FUNCTION
FUN3(
A,B)
RECURSIVE FUNCTION FUN4(X
,Y,Z
)
REAL RECURSIVE FUNCTION
FUN5(
M,N) RESULT(R_FUN5)
例:将一个
4字节的整数用16进制表示出来。
[e_622_01.f90]
FUNCTION
hex(
n)
CHARACTER(
LEN=8) ::
CHARACTER(LEN=1) :: h(0:15)=(/'0','1','2','3','4','5','6',&
'7','8','9','A','B','C','D','E','F'/)
INTEGER :
:
n,j,nn
hex
= '
'
DO j=8
,1
,-1
nn
=
n/16
hex(
j:j
)=h(n-16*
nn
)
IF(
nn
==0) EXIT
n=
nn
! 将n指定为INTENT(IN)将导致错误
END DO
END FUNCTION
PROGRAM main
CHARACTER(
LEN=8)::hex
!函数名的类型在调用单元也须加以声明
INTEGER::i
PRINT *,'Input a positive integer, or negative one to stop:'
READ *
,
i
; IF(
i
<0) EXIT
PRINT *
,hex
(
i
)
END DO
在本例中
,函数值
是赋给
函数名的,如果要
将值赋给
非函数名的另一结果名,则
FUNCTION
hex(
n) RESULT(
hx
)
CHARACTER(
LEN=8)::
hx
hx
(
j:j
)=
但在此例中就没有必要用函数了,可以用子程序,如:
SUBROUTINE
hex(
n,hx
)
CHARACTER(
LEN=8),INTENT(OUT)::
hx
例:分形图形的计算。分形
(fractal)是Mandelbrot将自然界的复杂图形(如海岸线,树叶形,雪花结晶型)进行数学理想化后提出的
一
种概念,其核心是图形的任意细小部分都与图形的整体具有自相似性,这种图形的维数不是整数,而是有分数维的。一个典型例子是Koch曲线,它有雪花形,可通过对一段直线反复进行某一简单操作而得到,把这个过程用数学语言描述,即为在复空间定义的一种简单迭代过程,它是一个图形的缩小映射,从而产生自相似曲线。一种简单的缩小映射是:
迭代过程是用
作为初始值代入得
,
然后反复将得到的值作为初始值代入得
一
序列复数值
,
,
,
,…。然后将此序列复数在复空间中绘出即得到相似曲线。程序中要计算迭代到n阶所需的迭代函数,其个数为
:用0记
,01记
,共有N+1个系数,其
系数呈杨辉
三角形形式:
1
1
1
2
1
1
3
3
1
1
4
6
4
1
1
5
10
10
5
1
这些系数间有明显的规律,即除了首尾两项系数为
1外,当N>1时,N阶中间各项系数是N-1阶的相应两项系数之和,也即如果把N阶的系数列为数组C(I,N),则除了C(1,N)和C(N+1,N)恒为1外,C(I,N)=C(I,N-1)+C(I-1,N-1)。当N=1时,只有两个取值为1的系数C(1,1)和C(2,1)。因此,任意N阶的系数可由N-1阶的系数求得,直到N=1为止,可写成递归子程序。[
e_624_03.f90]
类属过程是过程的一种,它允许用不同类型的实元与同一个哑元结合,也即放宽了哑实元结合时类型必须一致的条件。在内在基本函数中,已经有许多类属过程,例如求绝对值的函数
ABS(X),哑元为X,与它结合的实元可以是整型、实型与复型,也即使用同一个过程名ABS,调用函数ABS(-1)、ABS(-1.)、ABS(-1.,1.)都是合法的,并且一般来说,其函数值类型就取实元的类型,如上述前两个引用的函数值是1与1.0。
编写类属过程的方法是先编写着干个功能相同的过程,它们分别以整型、实型、复型等作哑元类型。而后在主调程序中编写接口,为接口取一个统一的名,接口内分别列出哑元类型不同的过程说明部分语句。这个统一的接口名就是类属过程名,可以在后面执行部分中用不同类型的实元作哑实结合。
例如,要编写求两数之和的类属函数时,分别编写哑元是实型和整型的函数:
FUNCTION
SUM_REAL(A,B) RESULT(SUM_REAL_RESULT)
REAL :: A,B,SUM_REAL_RESULT
SUM_REAL_RESULT=A+B
END FUNCTION
SUM_REAL
FUNCTION
SUM_INTEGER(A,B) RESULT(SUM_INTEGER_RESULT)
INTEGER :: A,B,SUM_INTEGER_RESULT
SUM_INTEGER_RESULT=A+B
FUNCTION SUM_INTEGER
现在把这两个函数过程综合成一个类属函数,类属函数名取为
MY_SUM,在主调程序应写明如下接口:
PROGRAM
SUMMATION
INTERFACE
MY_SUM
FUNCTION
SUM_REAL(A,B) RESULT(SUM_REAL_RESULT)
REAL :: A,B,SUM_REAL_RESULT
FUNCTION SUM_REAL
FUNCTION
SUM_INTEGER(A,B) RESULT(SUM_INTEGER_RESULT)
INTEGER :: A,B,SUM_INTEGER_RESULT
FUNCTION SUM_INTEGER
INTERFACE
IMPLICIT
REAL ::
INTEGER
:: I,J
READ *,
X,Y,I,J
PRINT *,
MY_SUM(X,Y),MY_SUM(I,J)
PROGRAM SUMMATION
主程序调用过程,称为第一层调用。被调用的过程可能也要调用更小的下属过程,这种调用称为第二层调用,依此类推。这样逐层调用下属过程,称为多层调用。
在多层调用中,函数可以调用下属的函数过程或子程序过程,子程序过程也可调用下属的函数过程或子程序过程,并不要求被调用的过程与自己的性质相同。多层调用中的程序控制流程是:控制从主程序
(第0层)的第一个执行语句开始,顺次往下执行,当遇到调用第一个第一层过程时,控制转入该过程的第一条可执行语句,并把第0层中的实元值赋给该第一层过程的哑元,顺次往下执行。如果再遇到调用第二层过程的语句,控制又转入该层过程的第一条可执行语句,并把第一层的实元值赋给第二层的哑元。如果最下一层子程序内没有调用语句,则控制遇到过程结束语句时,返回上层过程调用语句后,继续执行尚未执行的语句,直到第一层过程结束语句,控制再返回到主程序的调用语句,继续执行完后面的语句。直至遇到主程序结束语句,结束控制。
因此,这个控制机制是按顺序进行的,这一点也可由执行
Visual Fortran的Debug功能时,跟踪过程的顺序执行和变量的变化可见。
6.2.5
一个内部过程总是由程序单元中的语句来调用的。一般来讲,编译程序知道内部过程的一切情况,如知道该过程是一个函数或子程序、过程名、哑元的名字、变量类型和属性、函数结果的特性等等。这个信息的集合被称为过程的接口
(interface)。对于内部过程、内在过程和模块,过程接口对编译程序而言是己知的和显式给出的,故称
显式
接口。
由于主调程序与被调过程是分别编译的,而
F90扩充了过程的许多功能,这些功能单靠简单的调用语句无法反映,编译系统也无法知晓。如在调用一个外部过程或一个哑过程时,编译系统通常不知道该过程的各种情况,这种接口是
隐式
的。在F77中可用EXTERNAL语句来指明一个外部过程或哑过程,但此语句仅说明每一个外部名是一个外部过程名或哑过程名,并没有指明过程的接口,所以接口仍是隐式的。为了全面准确地通知编译系统,在主调程序中有时需要加入接口块,以说明主调程序与被调程序的接口。接口块是F90中引进的新颖程序块,它显式指明了过程接口的机制。通过接口块可用为一个外部过程或哑过程指明一个显式的接口。这比EXTERNAL语句提供了更多的信息,也提高了程序的可读性。
过程接口确定过程被调用的形式,它由过程的特性、过程名、各哑元的名字和特性以及过程的类属标识符
(可以省略)组成,一般它们都被写在一个过程的开头部分。此接口块被放在主调程序的说明部分中,通常还应写在类型说明语句之前,它的内容是被调用的过程中的说明部分,功能是通知编译系统,主调程序调用的过程中各种变元的类型、属性、性质等。
INTERFACE语句
接口块应写在主调程序
(主程序或过程)的说明部分中,一般是写在最前面:
PROGRAM 程序名
主调程序内变元说明
END PROGRAM
过程接口块的—般形式为:
INTERFACE [类属说明]
[接口体]…
[模块过程语句]…
END INTERFACE [类属说明]
其中类属说明的形式为:
类属名
->
类属过程
OPERATOR
->
超载操作符、自定义操作符
ASSIGNMENT(=)
->
超载赋值号
接口体的形式为:
[说明部分]
函数
END语句
子程序语句
[说明部分]
子程序
END语句
模块过程语句的形式为:
MODULE PROCEDURE 过程名表
。
这里,接口体是过程头的精确拷贝,定义了过程中的变量和函数结果。使用接口块时应该注意的是:
接口块以
INTERFACE语句开始,END INTERFACE语句结束,块内只能取被调用过程中的说明部分,不允许出现任何可执行语句。接口块内的语句构成接口体。
接口体中不能含有
ENTRY语句、DATA语句、FORMAT语句、语句函数语句。
接口块不允许出现在
BLOCK DATA程序单元中。
接口块中可以有多个接口体,即一个接口块中可以说明多个被调用过程,每个过程用自己的开始语句与结束语句定界,排列次序任意。
例:
interface
subroutine swap(
x,y
)
real
x,y
end subroutine
end interface
real
a,b
read *,
a,b
call swap(
a,b
)
subroutine swap(
x,y
)
real
x,y
z=
x;x
=
y;y
=z
end subroutine
例:求正方矩阵对角元的和
(trace)。
[e_625_01.f90]
例:
INTERFACE
SUBROUTINE EXT1(X,Y,Z)
REAL,DIMENSI0N(100,100)::X,Y,Z
END SUBROUTINE EXT1
SUBROUTINE EXT2(X,Z)
REAL X
COMPLEX(KIND=4) Z(2000)
END SUBROUTINE EXT2
FUNCTION EXT3(P,Q)
LOGICAL EXT3
INTEGER P(1000)
LOGICAL Q(1000)
END FUNCTION EXT3
END INTERFACE
这个接口块对于三个外部过程
EXT1、EXT2和EXT3说明了显式接口。它是无类属名的接口块。
接口块并不是每个主调程序都必须写的。若仅使用
F77语言编写的子程序,则无需在主调程序单元中写接口块。但若使用F90提供的现代化手段编写程序,通常需要在引用程序单元中写入接口块,否则编译容易出错,而且F90不提倡使用COMMON语句进行单元间的数据传递,其功能已由模块中的接口块代替。确切地说,凡遇下列情况之一时,主调程序必须有接口块:
1、如果外部过程具有以下特征:
过程的哑元有可选择属性。
过程的哑元是假定形数组、指针变量、目标变量。
函数过程的结果是数组或指针。
对于字符型函数过程的结果、其长度不是常数,也非假定长度
(*)。
2、如果调用过程时出现:
实元是关键字变元。
用一个类属名调用。
用超载赋值号
(对于子程序)。
用超载操作符
(对于函数)。
3、如果过程前缀关键词是ELEMENTAL。
超载操作符
超载操作符的形式仍是系统内部操作符,如
+
、
-、*、/等,但通过编出恰当的过程,可以扩充这些操作符的功能。例如;‘
+
’本来用于对数值作算术操作,但经恰当的编程后‘+’也可用于字符型操作,这就像车辆超载一样,故称为超载操作符。定义超载操作符,需先编写一个实现此超载
(扩充)功能的函数过程,再在主调程序中编写过程的接口,在接口语句后加上超载说明,其一般形式为:
INTERFACE OPERATOR(被超载使用的操作符号)
例如,要使‘
+’超载能执行如下操作:把两个字符串的最后一个字母接起来。实现超载时,先编一个能实现该操作功能的函数:
FUNCTION
ADD(A,B) RESULT(ADD_RESULT)
IMPLICIT
CHARACTER(LEN=*),INTENT(IN)
:: A,B
CHARACTER(LEN=2)
:: ADD_RESULT
ADD_RESULT=A(LEN_TRIM(A):LEN_TRIM(A))//B(LEN_TRIM(B):LEN_TRIM(B))
FUNCTION ADD
其中内在函数
LEN_TRIM为字符串去掉了尾部空格后的实际长度。现在要把这个函数功能定义为超载的操作符‘+’,则应在主调程序中编写如下接口块:
INTERFACE
OPERATOR(
+
)
FUNCTION ADD(A,B) RESULT(ADD_RESULT)
IMPLICIT NONE
CHARACTER(LEN=*),INTENT(IN) :: A,B
CHARACTER(LEN=2) :: ADD_RESULT
END FUNCTION ADD
INTERFACE
接口的作用是向编译系统提示,遇到操作符‘+’时,如果操作数不是数值,就不是原来意义的加法,操作含义要到
FUNCTION
ADD中找。当主调程序有了上述接口块后,在下面执行部分中执行字符串操作CH1+CH2时,+号作超载用。
[e_625_02.f90]
自定义操作符
如果用内部操作符超载后仍不能达到算法要求的功能,还可自定义一个新形式的操作符作崭新的操作。自定义新操作符可由字母组成,两边用小数点
(.)作定界符,以便与一般变量用关键字区别开来。它的形式与逻辑操作符.AND.、.OR.等形式一致。与我们可定义名义上的加法.add.,减法.minus.等。操作符名最多有31个字符组成,名称不得与FORTRAN关键字相同,如不可取.AND.或.GT.等。
[pi.f90]
超载赋值号
赋值号赋值号
(=)也可超载。根据规定,赋值号两边的类型必须相同,如两边都是数值型,或者都是逻辑型、字符型等。但F9O也允许使用超载赋值号,即允许把一个类型的表达式赋给另一类型的变量。例如,可以把逻辑表达式赋给一个数值型变量,并使之构成—一对应关系。
实现赋值号超载的方法是,先编一个实现两个不同类型变量值之间—一对应关系的子程序过程(非函数过程),而后在主调程序中编一个接口,用
ASSIGNMENT接口语句实现给赋值号定义不同的语义。接口语句的形式是:
INTERFACE ASSIGNMENT(=)
在具有
ASSIGMENT选择的接口块中,包含的子程序过程只有两个变元,第一个具有INTENT(OUT)或INTENT(INOUT)属性,第二个具有INTENT(IN)属性。作赋值运算时,第一个变元为被赋值的对象。
注意:要实现超载赋值号功能,必须编成子程序过程形式。相反,要实现超载操作符功能,必须编成函数过程形式,不可混用。
例:编一程序把逻辑量超载赋值给整型变量。先编一个实现这一功能的子程序
,
SUBROUTINE
LOG_INT(I,L)
IMPLICIT
LOGICAL, INTENT(IN) :: L
INTEGER, INTENT(OUT):: I
IF(L) I=1
IF(.NOT.L) I=0
END SUBROUTINE LOG_INT
再在主程序内编写接口
,
INTERFACE
ASSIGNMENT(=)
SUBROUTINE
LOG_INT(I,L)
IMPLICIT
LOGICAL, INTENT(IN) :: L
INTEGER, INTENT(OUT):: I
END SUBROUTINE LOG_INT
INTERFACE
此后,在主调程序内可任意赋值。此接口块定义的赋值运算与通常的赋值含义不同,但在程序中仍可用等号“
=”来使用。如I=1是通常的赋值,而I=.TRUE.是超载赋值,但I的取值认为1。
6.2.6
作用域单元
在用带有语句标号的
GOTO语句实现语句间的转移时会遇到这样一个问题,即程序中在什么情况下可以使用相同的语句标号而不会产生歧义?这就是语句标号的作用域问题。实际上主程序或每个过程都有—套独立的语句标号,包括宿主程序含有几个内部过程的情况。类似地,对变量名称也会有这样的问题,这就是名称的作用域问题。对于语句标号来说,它的作用域是主程序或过程,但不包括它含有的内部过程,相同的语句标号可以用在宿主程序和内部过程里而不会产生歧义。
F90标准以作用域单元的形式来定义名称。作用域单元是一个程序或程序的一部分,在作用域单元中定义一个名称,这个名称在作用域单元中有效。作用域单元可以是整个程序、程序单元、一个单独的语句或语句的一部分。名称可以是常量名、变量名、过程名、操作符或任何其它名称。名称可以用于程序、过程、变量、数组、哑元、命名常量、派生类型或块结构。名称有三种:全局名称、局部名称和语句名称。
作用域单元有以下几种:
1、派生类型定义;2、过程接口体,不包括其内部的派生类型定义和过程接口体;3、程序单元或过程,不包括内部的派生类型定义、过程接口体以及内部过程。
下面是包括
5个作用域单元的例子,作用域单元可以包含其他作用域单元。
MODULE
SCOPE1
!
Scoping unit 1
...
!
Scoping unit 1
CONTAINS
!
Scoping unit 1
FUNCTION
SCOPE2
!
Scoping unit 2
SCOPE3
!
Scoping unit 3
...
!
Scoping unit 3
END TYPE SCOPE3
!
Scoping unit 3
INTERFACE
!
Scoping unit 3
...
!
Scoping unit 4
END INTERFACE
!
Scoping unit 3
...
!
Scoping unit 2
CONTAINS
!
Scoping unit 2
SUBROUTINE
SCOPE5
!
Scoping unit 5
...
!
Scoping unit 5
END SUBROUTINE SCOPE5
!
Scoping unit 5
END FUNCTION SCOPE2
!
Scoping unit 2
MODULE
SCOPE1
!
Scoping unit 1
名称的作用域
全局名称用来识别程序单元、公共块和外部过程。全局名称在程序的任何地方都是有效的,所以只能在程序中定义一次。例如,如果用户在一个程序中使用了名为
Son的子程序,就不能再在该程序中使用名为Son的公共块或函数。
局部名称是用来识别变量
(标量和数组)、常量、命名常量、语句函数、内部过程、模块过程、哑元过程、内在过程、一般标识符、派生类型和名称列表组的名称。派生数据类型的成员和关键字变元(哑元)也是局部名称。局部名称可以覆盖全局名称和同一程序单元中的其它局部名称(关键字变元、类属名称和公共块名称除外)。如果一个名称对某个程序单元是局部的,同样的名称即可以作为全局名称又可以作为其它程序单元中的局部名称。
内在过程的双重名称
因为
FORTRAN语言的关键字不予保留,所以用户可以创建名称和FORTRAN内在过程名称一样的变量、常量或过程。一旦创建了这样的名称,原来的内在函数就不能再被访问。例如,下面定义了新的函数sin:
SUBROUTINE
CONTAINS
FUNCTION
sin(x)
FUNCTION sin
SUBROUTINE sub
任何在子程序
sub中对sin的引用都会调用其中定义的内部函数,而不是原来的内在函数。
类似地,任何与同名内在过程的标准类型不同的类型声明都会产生一个局部名称。下面的例子声明了一个名为
sin的变量:
CHARACTER(LEN=5)
:: sin
任何使用这个字符变量的程序或内部过程都不能再使用原来的内在函数。如果该变量在模块中以
PRIVATE属性声明,模块外的程序单元仍可以使用内在函数sin。
语句名称的作用域是一条语句。语句名称可以出现在语句函数的语句中、一个
DATA语句的隐DO循环中、一个数组构造器中。在语句函数语句中作为哑元出现的变量名,在其出现之处的范围就是语句域。DO变量的域(必须是整数)是隐DO列表。例如:
DIMENSION
x(10)
Add(
a,b
)=
a+b
n=1,10
x(n)=add(
y,z
)
END DO
在此例中,
a和b的域被限制在语句函数内部。n的域是整个DO循环。
公共块名称
公共块名称是全局名称。因为局部名称可以和全局名称重名,在局部实体中对这个名称的引用指的是局部名称。当公共块在
SAVE语句中命名时,它应该用斜杠围起来以和其它同名的局部变量区分。例如:
COMMON/happy/
cat,dog,mouse
CHARACTER(20) happy
SAVE /happy/
!SAVE的是公共块而不是变量
函数结果名
函数结果是另一个允许出现重名的例子。对每一个在函数过程中的
FUNCTION语句或ENTRY语句都可有一个结果变量。如果没有用RESULT指定另外的变量名,结果变量和函数定义时同名。
派生类型成员名称
如果一个变量是其它名称的成员,它的域和包含该变量的名称的域一样。例如,一个模块中定义的派生类型和模块的域一致,也和任何使用该模块的域一致;承认派生类型的的程序同样承认派生类型的成员;对于数组的情况也是类似的,在数组适用的域内,数组片段也是有效的。
其它实体,例如语句标号、
I/O单元、操作符和赋值号等都有域的概念。对于这些实体应遵守下面的规则:1、语句标号始终被认为是局部的,两个域相同的单元不能使用相同的标号;2、内在操作符(例如+,-,*,**,或/)是全局的,但自定义的操作符是局部实体,特殊操作符的域由定义该操作符的过程的范围决定。可以通过使用过程接口块使自定义的操作符成为全局的;3、赋值符号(=)是全局实体,可以在一个接口块中确定附加的一般赋值操作。