目录
前言
在子例程中,主程序通过带有参数列表的调用来实现与不同子例程的数据交换。
除了参数列表,在Fortran中还可以通过 模块MODULE 来交换数据。
模块是一个独立编译的程序单元,它包含了在程序单元间共享的数据的类型定义和初始值。
Fortran模块(MODULE)
1) 使用方式
常规用途是没有输入输出参数,仅用于共享数据,以供主程序、子例程等调用。
定义语句格式:
MODULE module_name ! 定义模块名
SAVE
(声明变量部分)
...
RETURN
END MODULE [ module_name ] ! []表示可选
注意事项:
-
module_name
由字母、数字和下划线组成 ,最大长度可达63个字符,第一个字符为字母; - 仅用于声明变量,没有计算执行部分;
-
SAVE
语句能够确保模块中声明的数据值在不同过程中引用时会被保留,应尽量留有这语句; - 由于模块中的变量是共享的,能够直接调用具体变量,因此在主程序、子例程等程序单元中,如果调用了该模块,定义局部变量时不能与模块中变量同名,否则会出错。
调用语句格式:USE module_name
注意事项:
-
USE
语句相当于是继承模块中的变量,因此变量名不能重复; - 为了在特定程序单元中访问数据,应该把
USE
语句放置在PROGRAM
、SUBROUTINE
、FUNCTION
语句后面的第一句位置处。
2) 模块示意
MODULE share_data
IMPLICIT NONE
SAVE
INTEGER , PARAMETER :: num_vals = 5 , PI = 3.141592
REAL , DIMENSION(num_vals) :: values
END MODULE share_data
3) 模块过程(显式接口)
在模块中定义子例程、函数等过程被称为模块过程。这些过程在模块中被完整定义,并使用包含模块名的USE
语句使得定义的模块过程在程序单元中有效。如对于模块子例程:
MODULE module_name ! 模块
IMPLICIT NONE
...(声明共享的数据)
CONTAINS
SUBROUTINE subroutine_name( parameter ) ! 子例程
...(声明、执行部分)
END SUBROUTINE subroutine_name
END MODULEmodule_name
PROGRAM main_name ! 主程序
USE module_name
...
CALL subroutine_name( parameter )
...
END PROGRAM main_name
注意事项:
-
CONTAINS
语句是告诉编译器后面的语句被包含在过程中,不能缺少; - 模块中的过程必须要接受模块中声明的任何数据对象;
- 必须先调用了模块,才能调用模块中的过程。
问:既然子例程能够在外部独立调用,为何多此一举?
答:原因是在模块中编译一个过程,当USE
该模块时,模块中定义的过程接口的所有细节对编译器都是有用的,编译器可以自动检测过程调用中的参数个数、类型、是否是数组、以及每个参数的INTENT
属性,可以通过检查接口来确保正确使用过程。
上述,一个在模块内编译和用USE
访问的过程称为带有显式接口(explicit interface)。
相对地,不在模块内的过程称为带有隐式接口(implicit interface)。隐式接口的使用前提条件是:保证过程定义形参和过程调用实参的变量一一对应(大小、类型、结构等信息)。一旦出错,程序会终止(不返回详细错误信息),有的甚至能成功运行但与预想相违背。如下例子:
隐式接口:
PROGRAM bad_call ! 主程序,错误示范
IMPLICIT NONE
REAL :: x = 1.
CALL bad_argument( x )
END PROGRAM bad_call
SUBROUTINE bad_argument ( i ) ! 子例程
IMPLICIT NONE
INTEGER :: i
WRITE(*,*) ' i = ' , i
END SUBROUTINE bad_argument
相应结果为:
i = 1065353216 ! 实参1.的内存地址
子例程定义的形参类型为整型,主程序调用子例程所输入的实参是实型,结果是程序传递实型参数的地址给了子例程,但子例程缺把它当做整型来处理,结果完全错误。
显式接口:
PROGRAM bad_call ! 主程序
USE mod1
IMPLICIT NONE
REAL :: x = 1
CALL bad_argument( x )
END PROGRAM bad_call
MODULE mod1 ! 模块
CONTAINS
SUBROUTINE bad_argument ( i ) ! 模块子例程
IMPLICIT NONE
INTEGER :: i
WRITE(*,*) ' i = ' , i
END SUBROUTINE bad_argument
END MODULE mod1
运行,弹出报错:
error #6633: The type of the actual argument differs from the type of the dummy argument. [X]
这是显式接口的优势,检查过程的变量数据是否匹配,例子中的报错显示实参x与形参的类型不一致。