Linux下C++和Fortran的混编

本文介绍了如何在C++ MPI并行代码中混编Fortran子程序,以利用CHEMKIN库的TRANLIB.F模块,解决复杂计算问题。通过实例和原理探讨,展示了如何处理不同语言间的函数调用规则和名称转换,以实现顺利编译和运行。

事情的起因是我需要计算多组分燃烧问题中的粘性项,实现起来非常麻烦。并且CHEMKIN中有现成的代码,但问题在于我的程序为.cpp的MPI并行代码。将Fortran代码翻译成C++代码再用也可,但是仅仅计算粘性的单独模块TRANLIB.F大概在2000行左右,改写起来很麻烦。

因此!干脆将C++和Fortran混编起来吧!为此专门研究了一下怎么弄

C语言和Fortran混编

C语言和Fortran混编的博客还是挺多的,虽然网上好像在互相抄同一段代码。似乎最早的源头是这篇https://www.cnblogs.com/xunxun1982/archive/2010/08/25/1808512.html

先贴出来代码:

//C语言部分,main.c文件
#include <stdio.h>
void sub_fortran_(int *,float *,double *);
double function_fortran_(double *);
int main(){
    int num_int;
    float num_float;
    double num_double;
    num_int = 3;
    num_float = 5.0;

    sub_fortran_(&num_int,&num_float,&num_double);
    num_double = function_fortran_(&num_double);
    printf("num_int=%d\n num_float=%f\n num_double=%f\n num=%f\n",num_int,num_float,num_double,num_double);
    return 0;
}

//Fortran部分,sub.f90文件
subroutine sub_fortran(NumInt,NumFloat,NumDouble)
    implicit none
    integer :: NumInt
    real :: NumFloat
    real(8) :: NumDouble
    NumDouble = NumFloat**NumInt
end subroutine

real(8) function function_fortran(NumDouble)
    implicit none
    real(8) :: NumDouble
    Function_Fortran = sqrt(NumDouble)
end function

然后直接编译运行如下:
在这里插入图片描述

其中-lm是为了调用数学库,在main.c中直接#include <math.h>也是可以的。原始的博客的代码是ok的,但是互相抄以后的其他博客有的代码有一些小bug,这里不多说。

解释一下原理,《Fortran95》彭国伦里面就有讲到。“所有的程序语言最后待会转换成汇编语言,也就是说到头来,他们都使用相同的语言。基于这一点,要混合使用不同的高级语言是可以做到的,因为事实上经过编译以后,他们都是使用汇编语言在相互通信”。就是说虽然Fortran和C语言的语法不同,但是当编译生成.o文件之后,是可以通用的。

虽然是这样说,但是也有一些需要注意的细节。Fortran语言的subroutine默认是传输变量的地址,而C语言则是传值,所以当C语言想调用Fortran中的函数时,必须注意对应传入的是地址。

最后是函数名,Fortran中的函数名为sub_fortran,而到了C语言中,却变成了sub_fortran_。这似乎是Fortran编译文件之后,为会在函数后面默认加上下划线,所以C语言调用时也得加上。反过来,如果是Fortran想要调用C语言中的函数时,要在函数前面加上下划线。而且虽然Fortran中不分大小写,但是C语言调用Fortran中函数时却区分大小写,函数名也要注意对应。

C++和Fortran混编

这个能查到的资料就不多了,最直观的想法就是直接把main.c改名改成main.cpp然后一样的方法编译。这样行不行呢?截图如下:
在这里插入图片描述
明明是一样的代码,.c时可以运行,但是.cpp就不行了。

实际上《Fortran95》彭国伦里面有提及一点点。C++和C对于函数名称的处理方法不同,C语言编译之后只会在函数名前面加上下划线,而C++则会给函数名后面加上一些字符串。因此Fortran代码中的子函数只在名字后面加下户线的方式就函数名不对应了。

解决办法也是比较简单。即使用extern "C",“是用来赋值在C++程序代码中编写C语言程序”,具体如下:

//main.cpp代码
#include <stdio.h>

#ifdef __cplusplus
extern "C"{
#endif

void sub_fortran_(int *,float *,double *);
double function_fortran_(double *);
int main(){
    int num_int;
    float num_float;
    double num_double;
    num_int = 3;
    num_float = 5.0;

    sub_fortran_(&num_int,&num_float,&num_double);
    num_double = function_fortran_(&num_double);
    printf("num_int=%d\n num_float=%f\n num_double=%f\n num=%f\n",num_int,num_float,num_double,num_double);
    return 0;
}

#ifdef __cplusplus
}
#endif

而Fortran代码部分维持原状,再次运行如下:
在这里插入图片描述
OK!成功了!

不过这只是初步尝试,CHEMKIN里面的Fortran代码段非常复杂,真正想混编估计没这么容易。先挖个坑,如果有时间了,再来补一下怎么将CHEMKIN中的TRANLIB.F混编进一个MPI并行的C++代码

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值