Fortran For Fun之fortran调用c

使用fortran和c混合编程可以利用一些现有的c和c++的库,减少代码量,提高编程效率。fortran调用c程序需要使用fortran编写程序接口,通常会用到 iso_c_binding这个模块。

以下以绑定linux系统的一个内置c函数usleep为例,说明fortran如何调用c程序

绑定为subroutine

该程序将usleep函数绑定为一个同名的子程序,绑定为subroutine时,subroutine的名称可以直接与c函数的名称一致,不一致时,需要在bind(c,name = )中定义c函数的名称。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
program learn_cbinding
use iso_c_binding
implicit none
interface
subroutine usleep(us) bind(c)
import c_int
integer(c_int), value :: us !< microseconds
end subroutine
end interface
real :: t1, t2, dt
t1 = wtime()
call usleep(nint(1E6))
t2 = wtime()
dt = t2 - t1
print"(a,f5.3,a)", 'Time elapse: ',dt, ' seconds'
call sleep(1) !< fortran inner sleep [seconds]
t1 = wtime();dt = t1 - t2
print"(a,f5.3,a)", 'Time elapse: ',dt, ' seconds'
contains
function wtime() result(o) !< Return the wall time
real :: o
integer :: count
real :: rate
call system_clock(count,rate)
o = count/rate
end function wtime
end program learn_cbinding

注意其中函数wtime中的 system_clock 的rate参数可以为实数了,这是fortran2008的一点改进。

结果

1
2
Time elapse: 1.000 seconds
Time elapse: 1.000 seconds

绑定为function

该程序中将 usleep函数绑定为doSleep函数,名称与原来的c函数不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
program learn_cbinding
use iso_c_binding
implicit none
interface
function doSleep(usec) result(e) bind(C,name='usleep')
use iso_c_binding
integer(c_int),value::usec
integer(c_int)::e
end function doSleep
end interface
integer :: info
real :: t1, t2, dt
t1 = wtime()
info = doSleep(nint(1E6))
t2 = wtime()
dt = t2 - t1
print"(a,f5.3,a)", 'Time elapse: ',dt, ' seconds'
call sleep(1)
t1 = wtime();dt = t1 - t2
print"(a,f5.3,a)", 'Time elapse: ',dt, ' seconds'
contains
function wtime() result(o) !< Return the wall time
real :: o
integer :: count
real :: rate
call system_clock(count,rate)
o = count/rate
end function wtime
end program learn_cbinding

结果

1
2
Time elapse: 1.000 seconds
Time elapse: 1.000 seconds

enumerator

fortran2003中借鉴c语言定义了一种枚举类型,枚举类型是一种整型常数,可以用来定义一组类似的常数类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
program learn_enumerators
implicit none
enum, bind(c)
enumerator :: one = 1
enumerator :: two = 2
enumerator :: thr = 3
enumerator :: fou = 4
end enum
print*,one
print*,two
print*,thr
print*,fou
end program learn_enumerators

结果

1
2
3
4
1
2
3
4