Dr.Shi's Studio.

Fortran学习笔记(二)

Word count: 948Reading time: 3 min
2023/03/07
loading

Fortran的子程序(subroutine)

Fortran 语言中的子程序事实上和C/C++语言的void类型函数类似:把需要重复使用的某些代码都集中成一个子程序,调用时可以给子程序初始化一些变量值从而获得不同的结果。比如说数值微分或者微分方程组的解法一类的数值计算代码就可以写成子程序的形式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
!!! 不带初始化变量的子程序
subroutine subr1
implicit none
real a, b
integer i
......
......
end subroutine subr1

!!! 带初始化变量的子程序
subroutine subr2(x, m, y, n)
implicit none
real x, y, a, b, z(10)
integer m, n, i, k
......
......
end subroutine subr2

!!! 调用子程序
real z
integer m
call subr1
m = 21
call subr2(10.0, 100, z, m*5+1)

子程序是以 subroutine 开头、以 end subroutine 结尾,其中第一行与一般主程序一样需要添加一行 implicit none 的声明。从上面的例子可以看出,无论是初始化还是没初始化变量,子程序都可以在主程序中被调用执行。只不过带初始化变量的子程序应该在被调用时给定相应的变量,否则无法正常被调用。子程序可以位于主程序代码片段之前或之后,不会影响在主程序中的正常调用。

如下所示是一个完整包含主程序和子程序的代码示例。主程序是以 program 开头、以 end program 结尾的代码片段。子程序代码不被包含在主程序代码片段中,但与主程序在同一文件中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
program stest1
implicit none
real x, y
x = 5.0
y = 100.0
call subr(x, y, 10)
print *, x, y
end program stest1

subroutine subr(x, y, n)
implicit none
real x, y
integer n
x = n
y = y*x
end subroutine subr

子程序的调用和主程序的执行顺序是:主程序 → 子程序 → 主程序。

由于子程序被调用时实际上不会与其他正在被执行的子程序相互干扰,所以可以在一个主程序中重复调用同一子程序。如果在子程序中需要根据某个条件判断中断退出,可以如下所示利用 if 语句和 return 关键字来返回主程序。

1
2
3
4
5
6
7
8
subroutine subr(x, y, m, n)
implicit none
real x, y
integer m, n
......
if (m < n) return
......
end subroutine subr

子程序中定义的局部变量和参数独立于主程序。也就是说,当我们在主程序和子程序中同时定义相同名称的变量时,其实它们之间也是不同的。只有当我们在调用子程序时使用主程序中同名的变量对参数进行赋值时,主程序和子程序的同名变量才会具有相同的值。

如下面的示例所示,编译执行的结果并非是期待的 10.0 和 30.0。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
!!! 示例 1
program stest1
implicit none
real x, y
x = 10.0
y = 30.0
call subr1
end program stest1

subroutine subr1
implicit none
real x, y
print *, x, y
end subroutine subr1

!!! 执行结果
>>> 2.80259693E-45 0.00000000

当我们修改为带初始化变量的子程序时,如霞示例所示,编译执行的结果和期待的一样。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
!!! 示例 2
program stest2
implicit none
real x, y
x = 10.0
y = 30.0
call subr2(x, y)
end program stest2

subroutine subr2(x, y)
implicit none
real x, y
print *, x, y
end subroutine subr2

!!! 执行结果
>>> 10.0000000 30.0000000

这两个例子的对比再一次证明了子程序中定义的变量所具有的局部性,必须通过参数传递的方式才能与主程序同名变量保持一样的初始化值。同样地,这种局部性也会让主程序的变量值不会因为子程序的同名变量值发生改变而改变。

TO DO ....

CATALOG
  1. 1. Fortran的子程序(subroutine)