Fortran调用C函数

时间:2022-07-22
本文章向大家介绍Fortran调用C函数,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

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 = %fn", *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 = %sn", 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).