我有一堆旧的 F77 源代码(通常在x86_64with上编译gfortran -std=legacy)。它包含相当多的形式功能:
double complex function f(x, y, i)
double precision x, y
integer i
f = cmplx(x, y) * i
return
end
我需要从一些 C++ 代码(通常在x86_64with上编译g++)调用这些函数。
它适用于默认的 Fortran
KIND=8:extern "C" { std::complex<double> f_(double *x, double *y, int *i); }当我
KIND=4使用以下-freal-8-real-4选项强制执行默认 Fortran 时,它可以工作:extern "C" { std::complex<float> f_(float *x, float *y, int *i); }当我
KIND=16使用该-freal-8-real-16选项(以及在 C++ 中#include <quadmath.h>)强制执行默认的 Fortran 时,它可以工作:extern "C" { __complex128 f_(__float128 *x, __float128 *y, int *i); }令我惊讶的是,在这种情况下,它似乎也可以使用(返回值在 中
*z):extern "C" { void f_(__complex128 *z, __float128 *x, __float128 *y, int *i); }上面这两个原型中哪一个是(更多?)正确的?
我的问题是我无法
KIND=10使用该-freal-8-real-10选项使其与我想要的默认 Fortran 一起工作。在 Fortran 内部kind,precision、range和sizeof返回值直接对应于 C++long double。所以,我尝试了:extern "C" { std::complex<long double> f_(long double *x, long double *y, int *i); } extern "C" { void f_(std::complex<long double> *z, long double *x, long double *y, int *i); } extern "C" { void f_(long double *x, long double *y, int *i, std::complex<long double> *z); }但我根本无法让它工作。
也许我需要向
gfortran和/或g++调用添加一些特殊标志,以便让 C++ 检索 FortranKIND=10复杂值?注意:我认为我不能使用-ff2c.
更新(2020.08.04):我已经能够欺骗 C++ 编译器,使它似乎可以为任何 Fortran 生成正确的代码KIND=4,8,10。诀窍是在 C++ 中使用 ISO C99 _Complex(注意:此技巧仅适用于KIND=10,但它实际上也适用于KIND=4,8):
#include <complex.h>
#define C99KIND long double /* it can be "float", "double" or "long double" */
extern "C" { C99KIND _Complex f_(C99KIND *x, C99KIND *y, int *i); }
请注意,在 C++ 中,您不能使用 eg long double complex,但幸运long double _Complex的是仍然可以。
C++中 ISO C99 的可用性_Complex相当有限。例如,使用-std=c++11(或更新)甚至最基本的creal*功能都cimag*消失了。
所以,最好的办法是立即将返回的值复制到一些标准的 C++ 模板化复杂变量中,例如使用类似的东西(注意:f_返回C99KIND _Complex):
std::complex<C99KIND> z = f_(&x, &y, &i);