我有一堆旧的 F77 源代码(通常在x86_64
with上编译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_64
with上编译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);