以下例子均来自网络,只是稍作了编辑,方便今后查阅。
子目录
(一) Fortran调用C语言
(二) C语言调用Fortran
(三) C++ 调用Fortran
(四) Fortran 调用 C++
需要说明的是,(一)和(二)对GCC编译器的版本要求并不高;而(三)和(四)对GCC编译器的要求比较高,需要GCC在4.7及以上才能编译通过,这是由于自Fortran 2003一代语言起,增加了一个名为“iso_c_binding”的模块,可以很方便地在Fortran和C++之间传递参数,简化了两者的混合编程。
————————————————————我是分割线———————————————————————————————
(一) Fortran调用C语言
源程序来自网络,增加了一个二维数组类型的调用示例。
Fortran文件(main.f90)的内容如下:
program main implicit none interface subroutine sub_c(n1,n2,n3) integer :: n1 real :: n2 real(8) :: n3 end subroutine real(8) function func_d(var2d) real(8) :: var2d(2,3) end function real(8) function func_c(n3) real(8) :: n3 end function end interface integer :: n1 real :: n2 real(8) :: n3,n4 real(8) :: var2d(2,3) n1=3 n2=5.0 call sub_c(n1,n2,n3) n4=func_c(n3) write(*,*) "n1=",n1 write(*,*) "n2=",n2 write(*,*) "n3=",n3 write(*,*) "n4=",n4 var2d=0 var2d(1,1)=dble(n1) var2d(1,2)=dble(n2) write(*,*) "var2d(1,:): ",var2d(1,:) write(*,*) "var2d(2,:): ",var2d(2,:) n2=func_d(var2d) write(*,*) "var2d(1,:): ",var2d(1,:) write(*,*) "var2d(2,:): ",var2d(2,:) end program main
C文件(sub.c)的内容如下:
#include <math.h> #include <stdio.h> void sub_c_(int *,float *,double *); double func_c_(double *); double func_d_(double [][2]); void sub_c_(int *n1,float *n2,double *n3) { *n3=pow(*n2,*n1); } double func_c_(double *n3) { double n4; n4=sqrt(*n3); return n4; } double func_d_(double var2d[3][2]) { double NN; NN=77.0; printf("%5.2f %5.2f %5.2f \n",var2d[0][0],var2d[1][0],var2d[2][0]); printf("%5.2f %5.2f %5.2f \n",var2d[0][1],var2d[1][1],var2d[2][1]); var2d[1][0]=NN; printf("%5.2f %5.2f %5.2f \n",var2d[0][0],var2d[1][0],var2d[2][0]); printf("%5.2f %5.2f %5.2f \n",var2d[0][1],var2d[1][1],var2d[2][1]); return NN; }
Makefile 文件的内容如下:
all: gcc -c sub.c -o sub.o gfortran -c main.f90 -o main.o gfortran -o main.exe main.o sub.o clean: rm *.o *.exe
编译并运行的结果如下:
[She@she-centos7 TestABC]$ make gcc -c sub.c -o sub.o gfortran -c main.f90 -o main.o gfortran -o main.exe main.o sub.o [She@she-centos7 TestABC]$ ./main.exe n1= 3 n2= 5.00000000 n3= 125.00000000000000 n4= 11.180339887498949 var2d(1,:): 3.0000000000000000 5.0000000000000000 0.0000000000000000 var2d(2,:): 0.0000000000000000 0.0000000000000000 0.0000000000000000 3.00 5.00 0.00 0.00 0.00 0.00 3.00 77.00 0.00 0.00 0.00 0.00 var2d(1,:): 3.0000000000000000 77.000000000000000 0.0000000000000000 var2d(2,:): 0.0000000000000000 0.0000000000000000 0.0000000000000000
注意:二维数组在Fortran和C中存储的方式不同,Fortran中是“列优先”,而C中是“行优先”。
在参数传递时,容易导致两者的引用错误。使用时要务必注意这个区别!!!
(二) C语言调用Fortran
示例1. 用结构体在C和Fortran之间传递参数
这种方法不需要对函数体进行预先声明,直接引用即可。由于结构体本身的最小存储单元的限制,在结构体内部的数据类型最好先作优化,以节省内存开销,原理可参见《C语言结构体占用空间内存大小解析》。
c2fortran.c
#include <string.h> struct test{ int n; float m; }; /* c2fortran.c */ int main(int argc,char *argv[]) { struct test t; t.n=90; t.m=0.003; int i; float e = 2.71828; char hello[32]; int length = sizeof(hello); strcpy(hello,"Hello Fortran from C"); for(i=strlen(hello); i<length; i++) hello[i] = ' '; showhie_(hello,&length,&e,&t); return(0); }
showhie.f
C showhie.f C SUBROUTINE SHOWHIE(HELLO,LENGTH,E,T) CHARACTER*(*) HELLO INTEGER LENGTH REAL E TYPE TEST INTEGER N REAL M END TYPE TYPE (TEST) :: T C WRITE(*,100) HELLO(1:LENGTH),LENGTH,E,T%N,T%M 100 FORMAT(3X,A,2X,I3,4X,F7.5,2X,I3,2X,F7.5) RETURN END SUBROUTINE SHOWHIE
Makefile_test 的内容:
fortran2c : c2fortran.o showhie.o gfortran c2fortran.o showhie.o -o c2fortran showhie.o : showhie.f gfortran -c showhie.f -o showhie.o c2fortran.o : c2fortran.c gcc -c c2fortran.c -o c2fortran.o clean : rm *.o
编译并运行的结果如下:
[She@she-centos7 TestABC]$ make -f Makefile_test gcc -c c2fortran.c -o c2fortran.o gfortran -c showhie.f -o showhie.o gfortran c2fortran.o showhie.o -o c2fortran [She@she-centos7 TestABC]$ ./c2fortran Hello Fortran from C 32 2.71828 90 0.00300
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; double num; num_int=3; num_float=5.0; sub_fortran_(&num_int,&num_float,&num_double); num=function_fortran_(&num_double); printf("num_int=%d\nnum_float=%f\nnum_double=%f\nnum=%f",num_int,num_float,num_double,num); return 0; }
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) ! 用gfortran编译报错,pgf90也同样无法编译,不知何故... Function_Fortran=NumDouble**0.5
end function
Makefile_CcallFortran
all: gcc –o main.o –c main.c gfortran –o sub.o –c sub.f90 gcc –o main2.exe main.o sub.o clean: rm *.o main2.exe
编译及运行结果:
num=15625.000000[She@she-centos7 TestABC]$ make -f Makefile_CcallFortran gcc -o main.o -c main.c gfortran -o sub.o -c sub.f90 gcc -o main2.exe main.o sub.o sub.o:在函数‘function_fortran_’中: sub.f90:(.text+0x75):对‘sqrt’未定义的引用 collect2: 错误:ld 返回 1 make: *** [all] 错误 1 [She@she-centos7 TestABC]$ make -f Makefile_CcallFortran gcc -o main.o -c main.c gfortran -o sub.o -c sub.f90 gcc -o main2.exe main.o sub.o [She@she-centos7 TestABC]$ ./main2.exe num_int=3 num_float=5.000000 num_double=125.000000
num=15625.000000
(三) C++ 调用Fortran
本例要求:gcc 和 gfortran 的编译器版本为4.7及以上。
fortran_matrix_multiply.f90
subroutine matrix_multiply(A, rows_A, cols_A, B, rows_B, cols_B, C, rows_C, cols_C) bind(c) use iso_c_binding integer(c_int) :: rows_A, cols_A, rows_B, cols_B, rows_C, cols_C real(c_double) :: A(rows_A, cols_A), B(rows_B, cols_B), C(rows_C, cols_C) C = matmul(A, B) end subroutine matrix_multiply
cpp_main_1.cpp
#include <iostream> #include <vector> #include <random> #include <ctime> using namespace std; //Fortran subroutine definition "translated" to C++ extern "C" { void matrix_multiply(double *A, int *rows_A, int *cols_A, double *B, int *rows_B, int *cols_B, double *C, int *rows_C, int *cols_C); } //Fill a vector with random numbers in the range [lower, upper] void rnd_fill(vector<double> &V, double lower, double upper) { //use system clock to create a random seed size_t seed (clock()); //use the default random engine and an uniform distribution default_random_engine eng(seed); uniform_real_distribution<double> distr(lower, upper); for( auto &elem : V){ elem = distr(eng); } }