事情的起因是我需要计算多组分燃烧问题中的粘性项,实现起来非常麻烦。并且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++代码
本文介绍了如何在C++ MPI并行代码中混编Fortran子程序,以利用CHEMKIN库的TRANLIB.F模块,解决复杂计算问题。通过实例和原理探讨,展示了如何处理不同语言间的函数调用规则和名称转换,以实现顺利编译和运行。
4610

被折叠的 条评论
为什么被折叠?



