前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Fortran调用C函数

Fortran调用C函数

作者头像
用户7592569
发布2020-07-27 15:14:29
3.3K0
发布2020-07-27 15:14:29
举报
文章被收录于专栏:量子化学量子化学

Fortran中调用C语言的函数这部分内容在彭国伦的教材中是有的,但那是基于Fortran 90标准,写法稍微有些烦琐。在Fortran 2003标准中有较为简洁的写法,本文通过几个简单的例子展示一下如何实现在Fortran中调C函数。

先上示例:

test.f90:

代码语言:javascript
复制
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:

代码语言:javascript
复制
# include <stdio.h>
void calC(float *a, float *b, float *c) 
{
    *c = *a + *b; 
    printf(" In C: a + b = %f\n", *c);
}

编译:

代码语言:javascript
复制
ifort -c test.f90 -o f.o
icc -c test.c -o c.o
ifort f.o c.o -o test.exe

运行生成的可执行文件test.exe,结果如下:

代码语言:javascript
复制
 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

代码语言:javascript
复制
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

代码语言:javascript
复制
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); 
}

运行结果如下:

代码语言:javascript
复制
 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).

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-01-19,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 量子化学 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档