调用C++具有复杂参数和复杂返回类型的函数 C 代码

Call C++ function with complex parameters and complex return type out of C code

本文关键字:复杂 函数 代码 返回类型 参数 C++ 调用      更新时间:2023-10-16

我有一个C++数学库,正在用 Rust 编写一个项目。由于不可能直接从 Rust 调用 C++,但调用 C 是可能的,我决定将一个标准包装器从 C++ 编写到 C 中。

一切都或多或少地按预期工作,除了具有复杂参数的函数,其中虚部由于某种原因丢失。下面我提供 mwe。

export_c++.h

#ifdef __cplusplus
#include <complex>
std::complex<double> foo(const std::complex<double> a);
#endif
#ifdef __cplusplus
extern "C" {
#endif
#include <complex.h>
double _Complex c_foo(const double _Complex a);
#ifdef __cplusplus
}
#endif

export_c++.cc

#include "export_c++.h"
#include <iostream>
std::complex<double> foo(const std::complex<double> a){
return a;
}
double _Complex c_foo(const double _Complex a){
std::complex<double> b{a};
double _Complex res{b.real(), b.imag()};
return res; 
}

现在我们将其编译为

g++ -c -std=gnu++11 -o export_c++.o export_c++.cc

并组装成库

ar rcs libexport_c++.a export_c++.o

我们将在main.c中使用它

#include "export_c++.h"
#include <stdio.h>
int main(int argc, char *argv[])
{
double complex a = 1. + I * 1.;
double complex b = c_foo(a);
printf("a = %f + I %fn", creal(a), cimag(a));
printf("b = %f + I %fn", creal(b), cimag(b));
return 0;
}

编译 main.c

gcc -o main -L. -lexport_c++ main.c

并运行

./main

这产生

a = 1.000000 + I 1.000000
b = 1.000000 + I 0.000000

我使用 macOS 并编译

Apple LLVM version 8.1.0 (clang-802.0.42)

这两个问题也与问题有些相关 标识符"creal"是未定义的 - 在Mac上可以看到,但在Linux上看不到,并且 C++ 和在单独的文件中

当然,作为一种解决方法,我可以将复杂参数分成两个double参数,因为无论如何我都会调用 rust 的代码。

顺便说一下,使用 gcc 7.1.0 进行编译

g++-7 -c -std=gnu++11 -o export_c++.o export_c++.cc
ar rcs libexport_c++.a export_c++.o
gcc-7 -o main -L. -lexport_c++ -lstdc++ main.c

产生预期结果

a = 1.000000 + I 1.000000
b = 1.000000 + I 1.000000

再添加一个源文件:

export_c++.h

//
// c and c++
//
struct complex_proxy
{
double real;
double imaginary;
};
#ifdef __cplusplus
extern "C" {
#endif
struct complex_proxy proxy_foo(struct complex_proxy a);
#ifdef __cplusplus
}
#endif
//
// c++ only
//
#ifdef __cplusplus
#include <complex>
std::complex<double> foo(const std::complex<double> a);
#else
#include <complex.h>
double _Complex c_foo(const double _Complex a);
#endif

export_c++.cpp

#include "export_c++.h"
std::complex<double> foo(const std::complex<double> a){
return a;
}

struct complex_proxy proxy_foo(struct complex_proxy a)
{
auto result = foo({a.real, a.imaginary});
return { result.real(), result.imag() };
}

export_c++.c

#include "export_c++.h"
double _Complex c_foo(const double _Complex a)
{
struct complex_proxy a_proxy = { creal(a), cimag(a) };
struct complex_proxy result = proxy_foo(a_proxy);
return result.real + result.imaginary * I;
}