我想从 python 调用一个使用复杂数组指针作为参数的 C++ 函数。
我的函数看起来像这样。
extern "C" void myfunction(complex<float> *arr)
我创建了一个名为
mylib.so
的库。
在 python 中,我有以下代码来调用库(如下:如何使用 ctypes 将 NumPy 复杂数组与 C 函数接口?):
complex_array = np.array([1+2j, 2+3j, 3+4j], dtype=np.complex64)
mylibrary_dll = CDLL('./mylib.so')
mylibrary_c = mylibrary_dll.myfunction
mylibrary_c.argtype = [np.ctypeslib.ndpointer(np.complex64,ndim=1,flags='c')]
我正在使用:
mylibrary_c(complex_array.ctypes.data_as(POINTER(c_float)))
阅读将 float* 转换为 std::complex 是否合法
我应该使用这样的东西吗:
complex_array = np.array([1+2j, 2+3j, 3+4j], dtype=np.complex64)
# I define a new stucture for complex
class Complex(ctypes.Structure):
_fields_ = [("real", ctypes.c_float),
("imag", ctypes.c_float)]
mylibrary_dll = CDLL('./mylib.so')
mylibrary_c = mylibrary_dll.myfunction
mylibrary_c.argtype = [POINTER(Complex)] # This is different from above
mylibrary_c(complex_array.ctypes.data_as(POINTER(Complex))) # This is different from above
如,在 C++ 中:
/// 26.2.3 complex specializations
/// complex<float> specialization
template<>
struct complex<float>
{
typedef float value_type;
typedef __complex__ float _ComplexT;
_GLIBCXX_CONSTEXPR complex(_ComplexT __z) : _M_value(__z) { }
_GLIBCXX_CONSTEXPR complex(float __r = 0.0f, float __i = 0.0f)
#if __cplusplus >= 201103L
: _M_value{ __r, __i } { }
#else
{
__real__ _M_value = __r;
__imag__ _M_value = __i;
}
#endif
将 Python 与需要复数数组的 C++ 函数连接时,必须注意确保 Python 的复数数组(由 NumPy 处理)和 C++ 的
std::complex<float>
数组之间的内存布局匹配。您对将 float*
转换为 std::complex<float>*
的担忧是有效的,因为 std::complex
的内存布局可能与表示 float
中复数的实部和虚部的两个连续
numpy
值不直接兼容数组。
ctypes.Structure
定义一个模仿
ctypes.Structure
内存布局的 std::complex<float>
是一种更可靠的方法,因为它保证了实部和虚部完全按照 C++ 函数的预期布局在内存中。这种方法比直接转换指针并希望兼容的内存布局更安全、更明确。
这是使用
ctypes.Structure
的方法的改进版本:
import numpy as np
import ctypes
from ctypes import CDLL, POINTER
# Define a structure that matches the memory layout of std::complex<float>
class Complex(ctypes.Structure):
_fields_ = [("real", ctypes.c_float), ("imag", ctypes.c_float)]
# Convert the NumPy array to the Complex structure array
def numpy_array_to_complex_struct_array(numpy_array):
return (Complex * len(numpy_array))(*[Complex(real=c.real, imag=c.imag) for c in numpy_array])
# Load the shared library
mylibrary_dll = CDLL('./mylib.so')
myfunction = mylibrary_dll.myfunction
# Specify the argument type
myfunction.argtypes = [POINTER(Complex)]
# Create a NumPy array of complex numbers
complex_array = np.array([1+2j, 2+3j, 3+4j], dtype=np.complex64)
# Convert and pass to the C++ function
complex_struct_array = numpy_array_to_complex_struct_array(complex_array)
myfunction(complex_struct_array)
Complex
结构显式定义内存布局以匹配std::complex<float>
,确保兼容性。numpy_array_to_complex_struct_array
函数处理从NumPy数组到Complex
结构数组的转换,从而更容易将数据正确地传递给C++函数。ctypes
与 C 库交互的文档可以作为了解如何同时使用 ctypes
和 NumPy 数组的有用参考。 NumPy C-API。ctypes
与 Python 中的 C/C++ 代码交互的更多详细信息。 Python ctypes 文档。std::complex
: 用于了解 C++ 中如何表示和处理复数。 C++ 参考 std::complex
。此方法提供了一种清晰且类型安全的方式来将 Python 与需要复数的 C++ 函数接口,从而最大限度地降低由于内存布局不匹配而导致未定义行为的风险。