从 python 调用一个使用复杂数组指针作为参数的 C++ 函数

问题描述 投票:0回答:1

我想从 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++ pointers
1个回答
0
投票

将 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++函数。

外部参考

  • NumPy 和 ctypes: NumPy 有关使用
    ctypes
    与 C 库交互的文档可以作为了解如何同时使用
    ctypes
    和 NumPy 数组的有用参考。 NumPy C-API
  • ctypes 文档: 有关如何使用
    ctypes
    与 Python 中的 C/C++ 代码交互的更多详细信息。 Python ctypes 文档
  • C++
    std::complex
    用于了解 C++ 中如何表示和处理复数。 C++ 参考
    std::complex

此方法提供了一种清晰且类型安全的方式来将 Python 与需要复数的 C++ 函数接口,从而最大限度地降低由于内存布局不匹配而导致未定义行为的风险。

© www.soinside.com 2019 - 2024. All rights reserved.