Fortran函数:子程序、函数——出自《Fortran 95 程序设计》 彭国伦

ScienceSoft 编程软件评论阅读模式

1.子程序subroutine的使用
program main
...
call sub1()
...
call sub2()
...
end program main

subroutine sub1()
...
end subroutine sub1

subroutine sub2()
...
end subroutine sub2

!子程序最后通常是return命令,返回调用它的地方,注意不是stop,如是stop则程序结束,结果难料。
!return可以省掉,可以出现在子程序的任何地方,提早返回。
exmaple:
subroutine message()
implicit none
write (*, *) "hello"
return
end 

子程序之间可以相互调用,子程序可在任何地方被别人调用,甚至可以自己调用自己,即“递归”。
子程序独立的拥有属于自己的变量声明,与其他程序互不相干,同时拥有自己的行代码。
参数传递:fortran 采用的是传址调用(call by address/call by reference),即调用时候传递出去的参数,和子程序中接收的参数使用相同的内存地址来记录数据。因此在主程序中传过来的参数,在子程序中可以被重新设置,主程序中参数内容跟着子程序中的改变而改变,在程序中可以改变主程序中的变量值。需要注意!!C采用的是传值调用,混合使用的时候需要注意。

2.自定义函数( FUNCTION)
自定义函数要先声明,再使用,执行后会返回一个数值。
program ex0807
implicit none
real :: a = 1
real :: b = 2
real, external :: add !声明add是一个函数,而不是变量。调用函数不必使用call命令。
write (*, *) add(a, b)
stop
end program ex0807

function add(a, b)
implicit none
real :: a, b   !输入的参数
real :: add   !add跟函数名称一样,这里不是用来声明变量,而是声明这个函数会返回的数值类型。
add = a+b
return
end function
!声明中多了一个external这个形容词,用来表示这里要声明的不是一个可以使用的变量,而是一个可以调用的函数。external可以省掉,但是建议不要省,容易辨别是函数而不是变量。

也可以这样声明上面的函数:
real function add(a, b)
implicit none
real :: a, b
add = a+b
return
end function

使用函数的一个不成文规定:“传递给函数的参数,只要读取就好,不要去改变它的数据”。如果要改变输入参数的数值时,最好使用子程序,而不是函数。

3.全局变量COMMON : 是f77中使用全局变量的方法,用来定义一块共享内存。
全局变量让不同程序声明出来的变量使用相同的内存位置,是一种不同程序之间传递参数的方法。
(1)common的使用:
program ex0810
implicit none
integer :: a, b
common a, b   !定义a,b是全局变量中的第一和第二个变量
...
call showcommon
...
stop
end program

subroutine showcommon()
implicit none
integer :: num1, num2
common num1, num2 !定义num1, num2是全局变量中的第一和第二个变量
write (*, *) num1, num2
return
end suroutine showcommon
!common的变量不可以随便用data的命令来设置他们的初值。取全局变量的时候,根据声明它们时的相对位置关系来作对应,而不是使用变量的名称来对应。任何一个地方改变了全局变量的值,程序中所有的程序都可以观察到这个变动,因为使用的是相同的内存位置。
!可以将变量归类,放在彼此独立的common区间中,避免麻烦。
exmaple:
integer :: a, b
common /group1/ a
common /group2/ b
....
stop
end

subroutine showgroup1()
....
common /group1/ num1
...
return
end

subroutine showgroup2()
...
common /group2/ num2
...
return
end

!当需要共享的数据不多,而且只有几个少数的程序需要使用这些数据的时候则使用参数传递。需要共享大笔数据,或是很多个不同的程序都需要使用这些数据的时候就使用全局变量。

4. block data
common设置初值:要在block data 程序模块使用data 命令来设置初值。
program ex0812
....
common a,b
common /group1/ c, d
common /group2/ e, f
....
stop
end

block data
implicit none
integer a,b
common a, b
data a, b /1, 2/
integer c, d
common /group1/ c, d
data c, d /3, 4/
integer e, f
common /group2/ e, f
data e, f /5, 6/
end block data

block data这一段程序是类似于子程序,是一个独立的程序模块,拥有自己的变量声明,不过不需要别人调用就可以自己执行。这段程序在主程序执行之前就会生效,但是功能只在于设置全局变量的初值,不能有其他的执行命令。
block data 的模样结构:
block data name     !name 可以省掉
implicit none
integer ...    !变量声明
real ...
common ...!把变量放到common空间中
common /group1/ ...
data var1, var2...       !同样使用data设定初值
...
end block data name ! 或end或end block data

!全局变量不可以声明成常量,所以block data 中不可以出现parameter.
!注意事项:变量的类型,变量的位置。 (!可以使用f90中的方法使用全局变量!)

5.函数中的变量
传递常数的时候要注意类型的正确性。
数组作为接收用的参数时候,可用变量来赋值它的大小,甚至不去赋值大小。
函数中接受到的参数,事实上它们的内存地址都在执行函数前配置完毕,因此参数在函数中的声明就不会再去配置新的内存来使用,所以可以使用变量来赋值数组的大小。甚至可以不赋值数组的大小,因为数组在进入子程序前就配置到了空间。在函数中赋值数组的大小只是用来方便检查,不会重新配置内存。
函数中使用数组参数时只要不超过它的实际范围就行,可以将一维变成二维(列优先),改变坐标范围等等。
一般传递数组时最好也顺便输入它原来声明的大小,函数中才会知道数组能使用的范围。
!传递字符串变量时也可以不特别赋值它的长度。
!多维数组在传递时只有最后一维可以不赋值大小,其他的都必须赋值大小。
!!建议将数组实际声明的大小全部传递出去是比较好的做法。!!

6.变量的生存周期
在声明中加上save可以增加变量的生存周期,保留住所保存的数据。
subroutine sub()
implicit none
integer :: count = 1
save count
....
end subroutine sub

或 integer, save :: count =1
每次子程序被调用时都会记得上次被调用时候留下来的数值。
注意:变量的初值只会设置一次,第一次调用的时候设置初值,不是每次都会去重新设置初值。

7.传递函数:类似于C中的函数指针。
可以把函数名称当作参数传递出去:
example:
program ex0821
real, external :: func !声明func是自定义函数 !形容词都不能省掉
real, intrinsic :: sin   !声明sin是库函数

call ExecFunc (func) !输入自定义函数func
call ExecFunc (sin)    !输入库函数sin

stop
end program

subroutine ExecFunc (f)
implicit none
real, external :: f   !声明参数f是个函数
write (*, *) f(1.0)   !执行输入的函数f
return
end

real function func (num)
implicit none
real :: num
func = num**2
return
end function

子程序也可以当作参数传递出去:
program ex0822
implicit none
external sub1, sub2   !声明sub1和sub2是子程序名称
call sub(sub1)
call sub(sub2)
stop
end program ex0822

subroutine sun (sun_name)
implicit none
external sub_name !声明 sub_name是个子程序
call sun_name ( )    !调用输入的子程序sub_name
return
end subroutine

subroutine sub1( )
implicit none
write (*, *) "sub1"
end subroutine

subroutine sub2( )
implicit none
write (*, *) "sub2"

end subroutine

 

via: encaidx的专栏

weinxin
我的微信公众号
分享科研软件、科研方法,为你的科研助力。
ScienceSoft
  • 本文由 发表于 10 11 月, 2015 09:32:21
  • 转载请务必保留本文链接:https://www.sciencesoft.cn/fortran-function-subroutine-compare/
评论  0  访客  0
匿名

发表评论

匿名网友 填写信息

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定