Fortran中调用C语言的函数这部分内容在彭国伦的教材中是有的,但那是基于Fortran 90标准,写法稍微有些烦琐。在Fortran 2003标准中有较为简洁的写法,本文通过几个简单的例子展示一下如何实现在Fortran中调C函数。
先上示例:
test.f90:
program main
implicit none
real(kind=4)::a,b,c
interface
subroutine calc(a,b,c) bind(c,name='calC')
use iso_c_binding
real(kind=c_float)::a,b,c
end subroutine calc
end interface
write(*,*) 'Enter a:'
read(*,*) a
write(*,*) 'Enter b:'
read(*,*) b
call calc(a,b,c)
write(*,*) "In Fortran: a+b= ",c
end
在这段Fortran代码中,尝试调用使用C语言编写的calc函数。对应的C语言的程序为:
test.c:
# include <stdio.h>
void calC(float *a, float *b, float *c)
{
*c = *a + *b;
printf(" In C: a + b = %f\n", *c);
}
编译:
ifort -c test.f90 -o f.o
icc -c test.c -o c.o
ifort f.o c.o -o test.exe
运行生成的可执行文件test.exe,结果如下:
Enter a:
1
Enter b:
2
In C: a + b = 3.000000
In Fortran: a+b= 3.000000
解读:
1. 在Fortran程序中需要给C函数写一个interface,在subroutine XXX后面跟上bind(c, name='YYY')语句,表示XXX这个子程序链接的是C语言中的YYY函数。注意XXX和YYY这两个名字可以毫无关系,且是区分大小写的。本例中Fortran中的名字为calc,而C语言中为calC,两者也是不同的。如果两者名字相同,可以省略name='YYY'语句。
2. iso_c_binding模块中,实际上定义了诸如c_float这些变量的数值,如果你很清楚C语言和Fortran中各种变量的大小,也可以不使用iso_c_binding模块。本例中,c_float即为4,因此在interface中可以直接将变量声明为real(kind=4)。
以下再展示一例关于结构体和字符串的传递。
test2.f90
module data_types
use,intrinsic::iso_c_binding
implicit none
type,bind(c)::my_type
integer(kind=c_int)::n
real(kind=c_float)::data1
real(kind=c_float)::data2
end type my_type
end module data_types
program main
use,intrinsic::iso_c_binding
use data_types
type(my_type)::test_struct
character(kind=c_char),dimension(20)::c
interface
subroutine c_sub(my_struct,msg) bind(c)
use,intrinsic::iso_c_binding
use data_types
type(my_type)::my_struct
character(kind=c_char),dimension(20)::msg
end subroutine c_sub
end interface
test_struct%n=3
test_struct%data1=6.0
test_struct%data2=0.0
c(1)='H'; c(2)='e'; c(3)='l'; c(4)='l'; c(5)='o'; c(6)=c_null_char
write(*,*) 'Output before the call:'
write(*,*) 'test_struct%n=',test_struct%n
write(*,*) 'test_struct%data1=',test_struct%data1
write(*,*) 'test_struct%data2=',test_struct%data2
call c_sub(test_struct,c)
write(*,*) 'Output after the call:'
write(*,*) 'test_struct%n=',test_struct%n
write(*,*) 'test_struct%data1=',test_struct%data1
write(*,*) 'test_struct%data2=',test_struct%data2
end
test2.c
typedef struct {
int n;
float data1;
float data2;
} MyType;
void c_sub(MyType *my_struct, char c[])
{
my_struct->data2 = my_struct->n * my_struct-> data1;
printf(" String = %s\n", c);
}
运行结果如下:
Output before the call:
test_struct%n= 3
test_struct%data1= 6.000000
test_struct%data2= 0.0000000E+00
String = Hello
Output after the call:
test_struct%n= 3
test_struct%data1= 6.000000
test_struct%data2= 18.00000
小编就不解读这段代码了,相信小伙伴们仔细看一下都会明白的。
参考资料:
Stephen J. Chapman, Fortran for Scientists and Engineers (4 ed).