Fortran中调用C语言的函数这部分内容在彭国伦的教材中是有的,但那是基于Fortran 90标准,写法稍微有些烦琐。在Fortran 2003标准中有较为简洁的写法,本文通过几个简单的例子展示一下如何实现在Fortran中调C函数。
先上示例:
test.f90:
program mainimplicit nonereal(kind=4)::a,b,cinterfacesubroutine calc(a,b,c) bind(c,name='calC')use iso_c_bindingreal(kind=c_float)::a,b,cend subroutine calcend interfacewrite(*,*) 'Enter a:'read(*,*) awrite(*,*) 'Enter b:'read(*,*) bcall calc(a,b,c)write(*,*) "In Fortran: a+b= ",cend
在这段Fortran代码中,尝试调用使用C语言编写的calc函数。对应的C语言的程序为:
test.c:
# include 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.oicc -c test.c -o c.oifort f.o c.o -o test.exe
运行生成的可执行文件test.exe,结果如下:
Enter a:1Enter b:2In C: a + b = 3.000000In 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_typesuse,intrinsic::iso_c_bindingimplicit nonetype,bind(c)::my_typeinteger(kind=c_int)::nreal(kind=c_float)::data1real(kind=c_float)::data2end type my_typeend module data_typesprogram mainuse,intrinsic::iso_c_bindinguse data_typestype(my_type)::test_structcharacter(kind=c_char),dimension(20)::cinterfacesubroutine c_sub(my_struct,msg) bind(c)use,intrinsic::iso_c_bindinguse data_typestype(my_type)::my_structcharacter(kind=c_char),dimension(20)::msgend subroutine c_subend interfacetest_struct%n=3test_struct%data1=6.0test_struct%data2=0.0c(1)='H'; c(2)='e'; c(3)='l'; c(4)='l'; c(5)='o'; c(6)=c_null_charwrite(*,*) 'Output before the call:'write(*,*) 'test_struct%n=',test_struct%nwrite(*,*) 'test_struct%data1=',test_struct%data1write(*,*) 'test_struct%data2=',test_struct%data2call c_sub(test_struct,c)write(*,*) 'Output after the call:'write(*,*) 'test_struct%n=',test_struct%nwrite(*,*) 'test_struct%data1=',test_struct%data1write(*,*) 'test_struct%data2=',test_struct%data2end
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= 3test_struct%data1= 6.000000test_struct%data2= 0.0000000E+00String = HelloOutput after the call:test_struct%n= 3test_struct%data1= 6.000000test_struct%data2= 18.00000
小编就不解读这段代码了,相信小伙伴们仔细看一下都会明白的。
参考资料:
Stephen J. Chapman, Fortran for Scientists and Engineers (4 ed).