返回介绍

6.2.5 过程接口

发布于 2025-03-08 16:28:36 字数 6839 浏览 0 评论 0 收藏 0

a) 接口形式

一个内部过程总是由程序单元中的语句来调用的。一般来讲,编译程序知道内部过程的一切情况,如知道该过程是一个函数或子程序、过程名、哑元的名字、变量类型和属性、函数结果的特性等等。这个信息的集合被称为过程的接口(interface)。对于内部过程、内在过程和模块,过程接口对编译程序而言是己知的和显式给出的,故称显式接口。

由于主调程序与被调过程是分别编译的,而 F90 扩充了过程的许多功能,这些功能单靠简单的调用语句无法反映,编译系统也无法知晓。如在调用一个外部过程或一个哑过程时,编译系统通常不知道该过程的各种情况,这种接口是隐式的。在 F77 中可用 EXTERNAL 语句来指明一个外部过程或哑过程,但此语句仅说明每一个外部名是一个外部过程名或哑过程名,并没有指明过程的接口,所以接口仍是隐式的。为了全面准确地通知编译系统,在主调程序中有时需要加入接口块,以说明主调程序与被调程序的接口。接口块是 F90 中引进的新颖程序块,它显式指明了过程接口的机制。通过接口块可用为一个外部过程或哑过程指明一个显式的接口。这比 EXTERNAL 语句提供了更多的信息,也提高了程序的可读性。

过程接口确定过程被调用的形式,它由过程的特性、过程名、各哑元的名字和特性以及过程的类属标识符(可以省略) 组成,一般它们都被写在一个过程的开头部分。此接口块被放在主调程序的说明部分中,通常还应写在类型说明语句之前,它的内容是被调用的过程中的说明部分,功能是通知编译系统,主调程序调用的过程中各种变元的类型、属性、性质等。

b) 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)

end

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 说明了显式接口。它是无类属名的接口块。

c) 必需接口

接口块并不是每个主调程序都必须写的。若仅使用 F77 语言编写的子程序,则无需在主调程序单元中写接口块。但若使用 F90 提供的现代化手段编写程序,通常需要在引用程序单元中写入接口块,否则编译容易出错,而且 F90 不提倡使用 COMMON 语句进行单元间的数据传递,其功能已由模块中的接口块代替。确切地说,凡遇下列情况之一时,主调程序必须有接口块:

1、如果外部过程具有以下特征:

过程的哑元有可选择属性。

过程的哑元是假定形数组、指针变量、目标变量。

函数过程的结果是数组或指针。

对于字符型函数过程的结果、其长度不是常数,也非假定长度(*)。

2、如果调用过程时出现:

实元是关键字变元。

用一个类属名调用。

用超载赋值号(对于子程序)。

用超载操作符(对于函数)。

3、如果过程前缀关键词是 ELEMENTAL。

d) 超载操作符

超载操作符的形式仍是系统内部操作符,如+、-、*、/等,但通过编出恰当的过程,可以扩充这些操作符的功能。例如;‘+’本来用于对数值作算术操作,但经恰当的编程后‘+’也可用于字符型操作,这就像车辆超载一样,故称为超载操作符。定义超载操作符,需先编写一个实现此超载(扩充) 功能的函数过程,再在主调程序中编写过程的接口,在接口语句后加上超载说明,其一般形式为:

INTERFACE OPERATOR(被超载使用的操作符号)

例如,要使‘+’超载能执行如下操作:把两个字符串的最后一个字母接起来。实现超载时,先编一个能实现该操作功能的函数:

FUNCTION ADD(A,B) RESULT(ADD_RESULT)

IMPLICIT NONE

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))

END 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

END INTERFACE

接口的作用是向编译系统提示,遇到操作符‘+’时,如果操作数不是数值,就不是原来意义的加法,操作含义要到 FUNCTION ADD 中找。当主调程序有了上述接口块后,在下面执行部分中执行字符串操作 CH1+CH2 时,+号作超载用。 [e_625_02.f90]

e) 自定义操作符

如果用内部操作符超载后仍不能达到算法要求的功能,还可自定义一个新形式的操作符作崭新的操作。自定义新操作符可由字母组成,两边用小数点(.) 作定界符,以便与一般变量用关键字区别开来。它的形式与逻辑操作符.AND.、.OR.等形式一致。与我们可定义名义上的加法.add.,减法.minus.等。操作符名最多有 31 个字符组成,名称不得与 FORTRAN 关键字相同,如不可取.AND.或.GT.等。 [pi.f90]

f) 超载赋值号

赋值号赋值号(=) 也可超载。根据规定,赋值号两边的类型必须相同,如两边都是数值型,或者都是逻辑型、字符型等。但 F9O 也允许使用超载赋值号,即允许把一个类型的表达式赋给另一类型的变量。例如,可以把逻辑表达式赋给一个数值型变量,并使之构成—一对应关系。

实现赋值号超载的方法是,先编一个实现两个不同类型变量值之间—一对应关系的子程序过程(非函数过程),而后在主调程序中编一个接口,用 ASSIGNMENT 接口语句实现给赋值号定义不同的语义。接口语句的形式是:

INTERFACE ASSIGNMENT(=)

在具有 ASSIGMENT 选择的接口块中,包含的子程序过程只有两个变元,第一个具有 INTENT(OUT) 或 INTENT(INOUT) 属性,第二个具有 INTENT(IN) 属性。作赋值运算时,第一个变元为被赋值的对象。

注意:要实现超载赋值号功能,必须编成子程序过程形式。相反,要实现超载操作符功能,必须编成函数过程形式,不可混用。

例:编一程序把逻辑量超载赋值给整型变量。先编一个实现这一功能的子程序,

SUBROUTINE LOG_INT(I,L)

IMPLICIT NONE

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 NONE

LOGICAL, INTENT(IN) :: L

INTEGER, INTENT(OUT):: I

END SUBROUTINE LOG_INT

END INTERFACE

此后,在主调程序内可任意赋值。此接口块定义的赋值运算与通常的赋值含义不同,但在程序中仍可用等号“=”来使用。如 I=1 是通常的赋值,而 I=.TRUE.是超载赋值,但 I 的取值认为 1。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文