Fortran编程:过程、数据与执行详解
立即解锁
发布时间: 2025-08-16 01:29:51 阅读量: 8 订阅数: 38 


Fortran 2003: 完整语法与特性指南
# Fortran编程:过程、数据与执行详解
## 1. 过程相关概念
### 1.1 内部过程
内部过程是在主程序、外部子程序或模块子程序中定义的过程。不过,内部子程序自身不能包含内部子程序。包含内部子程序的主程序、外部子程序或模块子程序被称为该内部子程序的宿主。通过宿主关联,宿主中已知的实体可被内部过程使用。内部过程可在其宿主内或同一宿主的其他内部过程中被调用。此外,还有一种已过时的特性——语句函数,它通过单条语句来指定一个函数。
### 1.2 过程接口
接口提供过程名、参数数量、参数类型、属性、名称以及函数结果的类型和属性等信息。在某些情况下,这些信息是必需的,例如对于会采用实际参数形状的虚参。这些信息还能让处理器检查调用的有效性。若过程接口并非固有可用,则可在接口块中进行指定。除块数据外,所有程序单元都可包含过程接口块。接口块用于描述外部过程、虚过程、过程指针、抽象过程或类型绑定过程的接口。带有通用规范的接口块可用于描述通用过程或用户定义的运算符、赋值或输入/输出。
### 1.3 通用过程
Fortran 有通用过程的概念,即一个过程能在不同调用中接受不同类型的参数。若该过程是函数,多数情况下结果类型与参数类型相同。例如,内置的 SIN 函数可接受实型、双精度型或复型参数。用户定义的过程也可以是通用的。用户定义多个特定过程,然后将它们的接口收集到带有通用规范的接口块中,或者在类型定义的 GENERIC 语句中列出。通用规范或 GENERIC 语句中出现的标识符可用于引用其参数与引用参数匹配的特定过程。
### 1.4 其他语言定义的过程
Fortran 可以访问用 C 语言定义的过程,C 程序也可以访问 Fortran 定义的过程。其他语言也可通过相同机制实现互操作,这些机制虽以 C 协议描述,但并不局限于 C 语言。Fortran 2003 为此过程所做的一些扩展,如虚参的 VALUE 属性、枚举和流输入/输出,对纯 Fortran 程序本身也很有用。
## 2. 数据环境
### 2.1 数据类型
Fortran 语言提供了五种固有数据类型:实型、整型、复型、逻辑型和字符型,同时允许用户定义其他类型。有时,将不同类型的多个组件组合起来组织数据是很自然的做法。在 Fortran 中,这种数据值的聚合被称为结构。要使用结构,程序员必须先定义其类型。定义新类型后,可声明任意数量该类型的结构(或对象)。有些应用需要相关对象,可定义一个基类型,然后通过添加不同组件进行扩展。通用过程可定义为接受基类型对象或其任何扩展作为实际参数,这种参数是多态的。
### 2.2 类型参数
固有类型和用户定义类型都可能有参数。对于固有类型,种类类型参数指定特定的表示形式,字符类型还有长度参数。每种固有类型可能有多种表示形式,由 KIND 参数指定。Fortran 标准要求实型和复型至少有对应“单精度”和“双精度”的两种不同表示形式,且允许更多。用户定义类型的类型参数可以是种类类型参数或长度类型参数,在类型定义中指定。种类类型参数值必须在编译时已知,可用于解析通用过程引用;长度类型参数值不必在编译时已知,可用于字符长度、数组维度等。若为延迟类型参数(用冒号 : 表示),其值可在执行期间改变;若为假定类型参数(用星号 * 表示),则从其他实体(如实际参数)获取值。以下是带参数的类型声明示例:
```fortran
complex (kind = HIGH) x
integer (kind = SHORT) days_of_week
character (kind = ISO_10646, len = 500) HAIKU
type MY_ARRAY (pick_kind, rows, cols) ! Type definition
integer, kind :: pick_kind
integer, len :: rows, cols
real (pick_kind) :: VALUES (rows, cols)
end type MY_ARRAY
type(MY_ARRAY) AA(HIGH, i, j)
```
其中,HIGH、SHORT 和 ISO_10646 是程序员赋予适当值的命名整型常量。字符字符串 HAIKU 的长度参数值为 500。AA 是 MY_ARRAY 类型,其单个组件 VALUES 是种类为 HIGH、维度为 (i, j) 的实型数组,i 和 j 是规范表达式。
### 2.3 维数
单个对象,无论是固有类型还是用户定义类型,都是标量。即使结构有组件,从技术上讲它也是标量。一组相同类型的标量对象可排列成包含列、行、平面和更高维配置的模式,从而形成数组。数组可以是结构数组,最多可有七个维度。维度数量称为数组的秩,在数组声明时确定且不可更改。数组的大小是元素总数,等于各维度范围的乘积。数组的形状是其范围列表。形状相同的两个数组称为可匹配,标量与任何数组都可匹配。以下是数组声明示例:
```fortran
real :: coordinates (100, 100)
integer :: distances (50)
type(line) :: mondrian(10)
```
数组是对象,可出现在表达式中或作为函数结果返回。对形状相同的数组进行的内置操作是逐元素执行的,结果数组形状相同,且逐元素操作的执行顺序没有隐含规定。数组的一部分(如元素或段)可作为数据对象被引用,数组元素是数组的单个元素,是标量;数组段是数组元素的子集,本身也是数组。
### 2.4 动态数据
数据对象在大小、形状、类型或长度类型参数方面可以是动态的,但秩和种类类型参数不能动态变化。动态数据对象包括多态对象、指针、可分配对象和自动对象。多态对象的类型在程序执行期间可能会改变。数据指针、可分配变量和虚参可能同时具有动态类型以及动态大小和形状。自动对象出现在子程序中,在子程序被调用时创建。动态类型是 Fortran 2003 引入的。非多态实体的声明类型和动态类型相同,未分配或未关联的多态对象的动态类型是其声明类型。使用 CLASS 关键字声明多态实体,用 CLASS (*) 声明的对象是无声明类型的无限制多态对象。
在 Fortran 中,过程和数据对象可声明为具有 POINTER 属性。过程指针必须是过程实体,数据指针在用于计算前必须与目标关联,可通过为目标分配空间或将指针赋值给现有目标来实现。指针赋值语句使用符号对 => 而非单个字符 =,它将指针与目标关联起来。例如:
```fortran
real, target :: VECTOR(100)
real, pointer :: ODDS(:)
. . .
ODDS => VECTOR(1:100:2)
```
此指针赋值语句将 ODDS 与 VECTOR 的奇数元素关联起来。赋值语句 `ODDS = 1.5` 会将 VECTOR 的每个奇数元素定义为 1.5。在执行序列的后期,只要目标是一维默认实型数组,指针 ODDS 可通过指针赋值或分配与不同目标关联。
若指针对象声明为数组,其大小和形状可动态变化,但秩由声明固定。若指针目标是多态的,指针必须是与目标兼容的类型,或者指针和目标都必须声明为无限制多态。以下是指针数组声明和分配的示例:
```fortran
real, pointer :: lengths (:)
allocate (lengths (200))
```
变量可声明为具有 ALLOCATABLE 属性,在用于计算前必须为其分配空间。程序执行时,该变量可被释放并重新分配,具有不同的类型、长度类型参数和形状。与指针一样,其秩由声明固定。可分配变量不能指向现有命名对象,必须通过 ALLOCATE 语句创建对象。以下是可分配数组声明和分配的示例:
```fortran
real, allocatable :: lengths (:)
allocate (lengths (200))
```
可分配数组和指针在某些用途上有相似之处,但也有区别。指针可用于创建动态数据结构,如链表和树,其目标可通过重新分配或指针赋值改变;可分配变量的属性只能通过释放和重新分配来改变。有一个 MOVE_ALLOC 内置函数,可在改变可分配数组大小时保留元素值。通常,使用可分配变量比使用更灵活的指针能带来更高效的执行。只有指针和可分配对象可以被分配或释放,还可以查询对象当前是否已分配。
自动数据对象(数组或字符串,或两者)可在子程序中声明。这些局部数据对象在子程序进入时创建,子程序执行完成后消失,适用于每次引用子程序时大小不同的临时数组和字符串。以下是一个带有自动数组 TEMP 的子程序示例:
```fortran
subroutine SWAP_ARRAYS (A, B)
real, dimension (:) :: A, B
real, dimension (size (A)) :: TEMP
TEMP = A
A = B
B = TEMP
end subroutine SWAP_ARRAYS
```
A 和 B 是假定形状的数组参数,TEMP 是在进入子程序 SWAP_ARRAYS 时创建的与 A 大小相同的自动数组,SIZE 是内置函数。
### 2.5 封装与信息隐藏
在规划新的 Fortran 应用程序时,对相当规模的程序进行封装是重要的设计考虑因素。封装的最重要好处是信息隐藏,可使实体仅在实际需要的地方可访问,从而防止意外误用或损坏,提高程序可靠性。封装还能通过隐藏底层复杂细节使程序的逻辑结构更清晰,便于理解和维护。提供这些好处的 Fortran 特性包括用户定义类型、内部过程和模块。
模块中用户定义类型的可访问性可以是公共、私有或受保护的。即使类型是公共的,它也可能有私有组件。类型定义有一个类型绑定过程部分,用于指定绑定到该类型的过程。内部过程可出现在主程序、模块子程序和外部子程序中,仅在其宿主内可见,其名称不能作为参数传递,且内部过程本身不能是另一个内部过程的宿主,但内部过程中可以出现语句函数。
模块提供了最全面的封装概念应用机会,包括多个层次的组织和隐藏。模块中指定的实体(类型、数据对象、过程、接口等)可以对其他作用域单元可用,可以可用但在模块外部受保护,也可以对模块私有。模块为面向对象应用中的实体提供了灵活的封装设施。类型定义中提到的类型绑定过程通常作为模块过程出现在包含该类型定义的模块中,除了普通过程的能力外,这些类型绑定过程还可以指定定义的运算符、定义的赋值、定义的输入/输出和终结操作。终结操作由终结过程完成,在对象因释放、执行 RETURN 或 END 语句或其他方式被销毁之前自动调用。
## 3. 程序执行
### 3.1 执行顺序
程序执行从主程序中的第一个可执行构造开始。可执行构造是执行一个或多个计算操作的指令,这些操作决定程序的行为或控制程序的执行流程,包括执行算术运算、比较值、分支到程序中的其他构造或语句、调用过程或读写文件或设备。以下是可执行语句的示例:
```fortran
read (5, *) z, y
x = (4.0 * z) + base
if (x > y) go to 100
call calculate (x)
100
y = y + 1
```
当调用一个过程时,其执行从过程入口点后的第一个可执行构造开始。正常从过程调用返回后,执行在调用过程中停止的地方继续。除非遇到改变执行流程的控制语句或构造,程序语句按其在程序单元中出现的顺序执行,直到执行 STOP、RETURN 或 END 语句。分支语句指定执行序列的改变,包括各种形式的 GO TO 语句、带有替代返回说明符的过程引用、EXIT 和 CYCLE 语句。
### 3.2 程序执行流程总结
为了更清晰地展示程序执行流程,下面给出 mermaid 格式的流程图:
```mermaid
graph TD;
A[开始] --> B[主程序第一个可执行构造];
B --> C{是否调用过程};
C -- 是 --> D[过程入口点后第一个可执行构造];
D --> E{过程执行结束};
E -- 是 --> F[返回调用处继续执行];
C -- 否 --> G{是否遇到控制语句};
G -- 是 --> H[按控制语句改变执行流程];
G -- 否 --> I[按顺序执行语句];
I --> J{是否执行 STOP/RETURN/END};
J -- 是 --> K[结束];
J -- 否 --> G;
H --> G;
```
### 3.3 动态数据对象操作对比
| 动态数据对象 | 创建方式 | 大小和形状变化 | 目标关联 | 特点 |
| --- | --- | --- | --- | --- |
| 指针 | 声明时指定 POINTER 属性 | 可动态变化,但秩固定 | 通过分配或赋值与目标关联 | 可创建动态数据结构,目标可灵活改变 |
| 可分配对象 | 声明时指定 ALLOCATABLE 属性 | 可通过释放和重新分配改变 | 只能通过 ALLOCATE 语句创建对象 | 操作相对固定,使用通常更高效 |
| 自动对象 | 在子程序中声明 | 随子程序调用创建和销毁 | 无 | 用于子程序临时存储,大小可变化 |
| 多态对象 | 使用 CLASS 关键字声明 | 类型可动态变化 | 无 | 类型灵活,可接受多种类型参数 |
### 3.4 过程调用与返回机制
过程调用是 Fortran 程序执行中的重要环节。当主程序或其他过程调用一个过程时,控制权会转移到被调用过程。被调用过程开始执行其内部的可执行构造,直到遇到返回语句(如 RETURN 或 END)。
过程调用的步骤如下:
1. **参数传递**:调用者将实际参数传递给被调用过程的虚参数。参数可以是变量、常量、数组等。例如在 `call calculate (x)` 中,变量 `x` 作为实际参数传递给 `calculate` 过程。
2. **进入过程**:控制权转移到被调用过程的入口点,从入口点后的第一个可执行构造开始执行。
3. **过程执行**:被调用过程执行其内部的计算和操作。
4. **返回结果(可选)**:如果过程是函数,它会返回一个结果给调用者。
5. **返回调用处**:当被调用过程执行完返回语句后,控制权返回到调用者,继续执行调用处之后的语句。
### 3.5 控制语句对执行流程的影响
控制语句在 Fortran 程序中用于改变执行流程,使程序能够根据不同的条件执行不同的操作。常见的控制语句包括:
- **GO TO 语句**:有多种形式,用于无条件地跳转到程序中的指定标签处。例如 `if (x > y) go to 100`,当条件 `x > y` 满足时,程序会跳转到标签为 100 的语句处继续执行。
- **EXIT 语句**:用于退出循环结构,当满足特定条件时,程序会立即跳出当前循环。
- **CYCLE 语句**:用于跳过当前循环的剩余部分,直接进入下一次循环。
下面是一个包含控制语句的示例:
```fortran
do i = 1, 10
if (i == 5) then
cycle ! 当 i 等于 5 时,跳过本次循环剩余部分,进入下一次循环
end if
if (i == 8) then
exit ! 当 i 等于 8 时,退出整个循环
end if
print *, i
end do
```
### 3.6 类型参数与动态数据的综合应用
类型参数和动态数据在 Fortran 中常常结合使用,以实现更灵活的编程。例如,在定义一个可动态调整大小的数组时,可以使用类型参数来指定数组元素的类型和精度,同时使用动态数据对象(如指针或可分配对象)来管理数组的大小和形状。
以下是一个综合应用的示例:
```fortran
program dynamic_array_example
implicit none
integer :: n = 10
real, allocatable :: array(:)
! 分配数组空间
allocate(array(n))
! 初始化数组元素
do i = 1, n
array(i) = real(i)
end do
! 输出数组元素
print *, array
! 释放数组空间
deallocate(array)
end program dynamic_array_example
```
在这个示例中,使用了可分配对象 `array` 来创建一个动态数组,通过 `allocate` 语句分配空间,使用完后通过 `deallocate` 语句释放空间。同时,数组元素的类型为 `real`,可以根据需要通过类型参数指定不同的精度。
### 3.7 封装特性的实际应用场景
封装特性在 Fortran 编程中有着广泛的应用场景,以下是一些常见的应用场景:
- **数据保护**:通过将数据对象和过程封装在模块中,并设置合适的访问权限(公共、私有或受保护),可以防止外部程序对数据的意外修改。例如,将一些敏感数据和操作这些数据的过程封装在一个私有模块中,只有模块内部的过程可以访问和修改这些数据。
- **代码复用**:模块可以包含多个相关的类型、数据对象和过程,其他程序单元可以通过使用模块来复用这些代码。例如,将一些常用的数学函数封装在一个模块中,其他程序可以通过 `use` 语句使用这些函数。
- **面向对象编程**:利用模块和类型绑定过程可以实现面向对象编程的一些特性,如封装、继承和多态。例如,定义一个基类型和多个扩展类型,并为这些类型定义类型绑定过程,实现不同类型对象的统一操作。
### 3.8 总结
Fortran 是一门功能强大的编程语言,具有丰富的过程、数据和执行相关的特性。通过合理使用内部过程、通用过程等过程概念,可以提高代码的模块化和可复用性。数据环境方面,数据类型、类型参数、维数和动态数据等特性为编程提供了灵活性和高效性。在程序执行过程中,了解执行顺序、控制语句和过程调用机制等内容,可以更好地控制程序的流程和行为。封装特性则有助于提高程序的可靠性和可维护性。
在实际编程中,我们可以根据具体的需求选择合适的特性和方法。例如,对于需要处理动态数据的场景,可以使用指针和可分配对象;对于需要实现代码复用和信息隐藏的场景,可以使用模块和封装特性。通过不断学习和实践,我们可以更好地掌握 Fortran 编程,开发出高质量的程序。
### 3.9 未来展望
随着计算机技术的不断发展,Fortran 也在不断演进。未来,Fortran 可能会进一步加强与其他编程语言的互操作性,支持更多的并行计算模型,以满足科学计算和工程应用的需求。同时,在数据处理和算法优化方面,Fortran 也可能会引入更多的新特性和工具,提高编程的效率和性能。
对于开发者来说,需要不断关注 Fortran 的发展动态,学习和掌握新的特性和技术,以适应不断变化的编程需求。同时,也可以结合其他编程语言的优势,实现更加复杂和高效的应用程序。
### 3.10 学习建议
- **多实践**:通过编写实际的代码来加深对 Fortran 特性的理解和掌握。可以从简单的程序开始,逐步增加复杂度。
- **阅读优秀代码**:参考一些优秀的 Fortran 代码示例,学习他人的编程思路和技巧。
- **参与社区**:加入 Fortran 编程社区,与其他开发者交流经验和心得,获取最新的技术信息。
通过以上的学习方法和实践,相信大家可以更好地掌握 Fortran 编程,开发出高质量的程序。
0
0
复制全文
相关推荐










