C++ 调用Fortran函数,从C++;

C++ 调用Fortran函数,从C++;,c++,fortran,g++,gfortran,mixed-programming,C++,Fortran,G++,Gfortran,Mixed Programming,我有一堆旧的F77源代码(通常使用gfortran-std=legacy在x86_64上编译)。 它在形式上包含许多函数: 双复函数f(x,y,i) 双精度x,y 整数i f=cmplx(x,y)*i 返回 结束 我需要从一些C++代码中调用这些函数(通常是在 x8664 64 < /COD>中使用 g++< /COD> >)。 它使用默认的FortranKIND=8: extern“C”{std::complex f_(double*x,double*y,int*i);} 当我使用-fr

我有一堆旧的F77源代码(通常使用
gfortran-std=legacy
x86_64
上编译)。 它在形式上包含许多函数:

双复函数f(x,y,i) 双精度x,y 整数i f=cmplx(x,y)*i 返回 结束 我需要从一些C++代码中调用这些函数(通常是在<代码> x8664 64 < /COD>中使用<代码> g++< /COD> >)。

  • 它使用默认的Fortran
    KIND=8

    extern“C”{std::complex f_(double*x,double*y,int*i);}
    
  • 当我使用
    -freal-8-real-4
    选项强制使用默认Fortran
    KIND=4
    时,它会起作用:

    extern“C”{std::complex f_(float*x,float*y,int*i);}
    
  • <> L> > P>在执行默认Fortran <代码>类型= 16 时使用<代码> -FRIAL-8Realth16选项(并且在C++ <代码>包含< /代码>):

    extern“C”{uuuuuu complex128 f_uuu(uuu float128*x,uuu float128*y,int*i)}
    
    令我惊讶的是,在本例中,它似乎也适用于(返回值位于
    *z
    ):

    extern“C”{void f_u(uuu complex128*z,uuu float128*x,uuu float128*y,int*i)}
    
    以上两个原型中哪一个是(更多?)合适的

  • 我的问题是,我无法使用
    -freal-8-real-10
    选项使用所需的默认Fortran
    KIND=10
    。在FORTRAN内部,<代码>类<代码> >代码>精度<代码>,<代码>范围<代码> >代码> sieOS/<代码>返回值,它直接对应于C++ <代码>长双< /代码>。所以,我试着:

    extern“C”{std::复数f_(长双精度*x,长双精度*y,int*i);}
    外部“C”{void f_uz(std::complex*z,long double*x,long double*y,int*i)}
    extern“C”{void f_(长双精度*x,长双精度*y,int*i,std::complex*z);}
    
    但我根本无法让它工作

    也许需要添加一些特殊的标志到<代码> gfortran < /COD>和/或<代码> G++< /Corp>调用,以便让C++检索FORTRAN <代码> Type=10 < /COD>复杂值 注意:我认为我不能使用

    -ff2c

  • <强>更新(2020.0804)< /强>:我已经能够欺骗C++编译器,以便它似乎为任何fortran <代码> Orth= 4,8,10< /代码生成适当的代码。诀窍是在C++中使用ISO C99 <代码>复数< /COD>(注:此技巧仅适用于<代码>类=10 < /COD>,但它实际上适用于<代码>类型=4,8< /代码>:

    #包括
    #定义C99KIND long double/*它可以是“float”、“double”或“long double”*/
    外部“C”{C99KIND_复形f_(C99KIND*x,C99KIND*y,int*i);}
    
    <>请注意,在C++中,不能使用例如<代码>长双复数< /C> >但幸运的是,代码> long double double复合体仍然很好。

    <> C++中的ISO999代码>复杂的< /代码>的可用性相当有限。例如,使用
    -std=c++11
    (或更新版本),即使是最基本的
    creal*
    cimag*
    函数也会消失

    <> >最好的办法是立即将返回的值复制到一些标准的C++模板复变量中,例如使用(如:<代码> fy< <代码>返回>代码> c99类复合体< /代码>):

    std::complex z=f_(&x,&y,&i);
    
    如果您想正确地完成这项工作,请学习如何实际使用Fortran的种类类型参数,并将Fortran代码正确地移植到REAL(10)。是的,我知道
    10
    不可携带;然而,我们正在讨论一种特殊的Fortran处理器

    考虑一下

    function f(x, y, i) result(r) bind(c, name='f')
      use iso_c_binding, only : ep => c_long_double
      implicit none
      complex(ep) r
      real(ep), intent(in), value :: x, y
      integer, intent(in), value :: i
      r = cmplx(x, y, ep) * i
    end function f
    
    <>和,因为我不做C++,但是你应该能够更新C到你的需要

    #include <complex.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    long double complex f(long double, long double, int);
    
    int
    main(void)
    {
      int i;
      long double x, y;
      long double complex z;
    
      i = 42;
      x = 1;
      y = 2;
      printf("%.10Lf %.10Lf\n", x, y);
    
      z = f(x, y, i);
      x = creall(z);
      y = cimagl(z);
      printf("%.10Lf %.10Lf\n", x, y);
      return 0;
    }
    
    % gfortran -c a.f90
    % gcc -o z b.c a.o -lm
    % ./z
    1.0000000000 2.0000000000
    42.0000000000 84.0000000000
    
    #包括
    #包括
    #包括
    长双复数f(长双复数,长双复数,int);
    int
    主(空)
    {
    int i;
    长双x,y;
    长双复z;
    i=42;
    x=1;
    y=2;
    printf(“%.10Lf%.10Lf\n”,x,y);
    z=f(x,y,i);
    x=creall(z);
    y=cimagl(z);
    printf(“%.10Lf%.10Lf\n”,x,y);
    返回0;
    }
    %gfortran-c a.f90
    %gcc-o z b.c a.o-lm
    %./z
    1.0000000000 2.0000000000
    42.0000000000 84.0000000000
    
    OP声明他不能为自己的Fortran代码的正确端口而烦恼,因此,必须使用编译器选项神奇地(是的,这是神奇的)进行端口操作。这里有一个例子

    % cat a.f90
    double complex function f(x, y, i)
      implicit none
      double precision :: x, y
      integer i
      f = cmplx(x, y) * i   ! cmplx my not do what you expect
    end function f
    
    % cat b.c
    #include <complex.h>
    #include <stdio.h>
    #include <stdlib.h>
    
    long double complex f_(long double *, long double *, int *);
    
    int
    main(void)
    {
      int i;
      long double x, y;
      long double complex z;
    
      i = 42;
      x = 1;
      y = 2;
      printf("%.10Lf %.10Lf\n", x, y);
    
      z = f_(&x, &y, &i);
      x = creall(z);
      y = cimagl(z);
      printf("%.10Lf %.10Lf\n", x, y);
      return 0;
    }
    
    % gfcx -c -freal-8-real-10 a.f90
    % gcc -o z b.c a.o -lm
    % ./z
    1.0000000000 2.0000000000
    42.0000000000 84.0000000000
    
    %cat a.f90
    双复函数f(x,y,i)
    隐式无
    双精度::x,y
    整数i
    f=cmplx(x,y)*i!cmplx我的不是你所期望的
    端函数f
    %b.c.类
    #包括
    #包括
    #包括
    长双复数f_2;(长双*,长双*,int*);
    int
    主(空)
    {
    int i;
    长双x,y;
    长双复z;
    i=42;
    x=1;
    y=2;
    printf(“%.10Lf%.10Lf\n”,x,y);
    z=f_z(&x,&y,&i);
    x=creall(z);
    y=cimagl(z);
    printf(“%.10Lf%.10Lf\n”,x,y);
    返回0;
    }
    %gfcx-c-freal-8-real-10 a.f90
    %gcc-o z b.c a.o-lm
    %./z
    1.0000000000 2.0000000000
    42.0000000000 84.0000000000
    
    还是去参加三足鼎立吧。下面是C++代码,与第二个例子中的文件A.F90一起使用。
    #include <iostream>
    #include <complex>
    #include <cmath>
    
    extern "C" { std::complex<long double> f_(long double *, long double *, int *); }
    
    int main()
    {
      std::complex<long double> z;
      long double x, y;
      int i;
    
      i = 42;
      x = 1;
      y = 2;
      z = f_(&x, &y, &i);
    
      std::cout << z << '\n';
     }
    
    #包括
    #包括
    #包括
    外部“C”{std::复数f_10;(长双精度*,长双精度*,int*);}
    int main()
    {
    std::复z;
    长双x,y;
    int i;
    i=42;
    x=1;
    y=2;
    z=f_z(&x,&y,&i);
    
    std::我想问题是,即使80位FPU计算可能用于
    长双精度
    sizeof(长双精度)
    ,因此存储布局与Fortran的不匹配。不知道是否有任何开关将
    长双精度
    存储为10字节。为什么希望种类=10?但实现这一点的方法不是随机选取种类和编译器标志,而是FortranYes定义的标准方法,
    sizeof(长双精度)在C++中,为16,但FORTRAN返回的值为<代码>实数(类型=10)< /代码>。