Fortran与C/C++混合编程示例

本文详细介绍了如何在Fortran中调用C/C++代码,以及C/C++调用Fortran的实例,包括二维数组传递、结构体和指针变量的使用。混合编程需要注意GCC版本要求,以及不同语言间数据存储方式的差异,如Fortran的列优先和C的行优先。同时,文章提供多个示例代码和Makefile,帮助读者理解和应用。
摘要由CSDN通过智能技术生成

以下例子均来自网络,只是稍作了编辑,方便今后查阅。

   子目录

(一) 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

 

示例2. 用指针变量在C和Fortran之间传递参数  

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

示例1. 调用Fortran函数生成一个NxN的矩阵

本例要求: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);
     }
 }
 
 
  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值