有时候,我们希望使用Fortran和C/C++混合编程,以利用各语言的优势。只要确保函数调用时传递的参数类型正确,定义和声明的变量类型和大小匹配,Fortran和C 语言二者的函数和全局变量就可以彼此直接相互调用,所以混合编程可以非常容易地实现。至于主函数在C文件中还是Fortran文件中,依具体使用情况而定。
1、编译器:Intel Fortran、GNU Fortran、gcc/g++,操作系统Linux
1.1 Intel Fortran
使用ifort链接,主函数必须在Fortran文件中;
使用gcc/g++链接,主函数必须在C/C++文件中,根据Fortran代码中使用的库文件的情况,需要显式链接各库。可以使用ldd查看库文件的依赖关系,并把依赖的库链接进来。
ifort -c file.f90 -o f.o
gcc/g++ -c file.c -o c.o
ifort f.o c.o -o a.out -lc -lstdc++ //链接C/C++标准库
//-L指定库所在位置,-l指定要链接的库名
g++ -o a.out file.cpp f.o -L/opt/intel/mkl_10.3.1.048/lib -lifcore -ldl
1.2 GNU Fortran
GNU Fortran和GNU C/C++可以互相编译对方语言代码,因此既可以像ifort那样和C/C++分别编译后链接,也可以只用其中一个完成编译链接;
使用gfortran编译C/C++文件时,.c文件默认使用c编译器,.cpp文件默认使用c++编译器。
gfortran file.c file.f90 -o a.out //C标准库不需要显式链接
gfortran file.cpp file.f90 -o a.out -lstdc++ //必须链接C++标准库
1.3 gcc/g++
根据需要连接Fortran标准库
//主函数在c/c++文件中
gcc/g++ file.c file.f90 -o a.out -lgfortran
gcc file.cpp file.f90 -o a.out -lgfortran -lstdc++ //必须链接C++标准库
//主函数不在c/c++文件中
gcc/g++ file.c file.f90 -o a.out -lgfortranbegin -lgfortran
gcc file.cpp file.f90 -o a.out -lgfortranbegin -lgfortran -lstdc++
2、编译相关和修饰规则
以如下文件为例,来看看编译后C和Fortran在目标文件中修饰规则
//file.cpp
int itest = 0;
extern int iii;
extern void c_func1(float*, int); //使用C++的编译修饰规则,Fortran无法调用
extern "C" int c_func2() //使用C的编译修饰规则, Fortran可以调用
{
float ff;
c_func1(&ff, itest );
}
//file.f90
module mod_f
implicit none
real ra, rb
complex cplf
contains
subroutine f_sub()
cplf = cmplx(sin(ra), cos(ra))
end subroutine f_sub
end module mod_f
complex function f_func(argument)
use mod_f
implicit none
real argument, comm1, comm2
common /comm/ comm1, comm2
ra = sqrt(2.) / 2.
call f_sub()
f_func = cplf
end function f_func
编译后的目标文件内容:
通过上图,在默认编译选项下,可以看出:
1、gfortran和ifort对module中的变量有不同的修饰,且gfortran无后缀“下划线”;
2、gfortran和ifort对COMMON公共区名和函数/子例程名都有后缀“下划线”修饰,而C对全局变量和函数名没有进行修饰;
3、为了保证链接成功,需要在C代码中对在混合编程中进行交换信息的全局变量和函数名后缀“_”(module中变量还有前置修饰);
4、C++编译修饰后的函数名无法在Fortran和C中调用。
当然可在Fortran编译选项中指定不后缀“下划线”,这样C代码中相应变量和函数名称就无需后缀“_”。
gfortran -fno-underscoring -c file.f90
ifort -assume nounderscore -c file.f90
注:gcc/g++ 通过编译选项只能在名称前面加“下划线”修饰。