【问题标题】:Ctypes: Extended Struct/Pointer (Inheritance)Ctypes:扩展结构/指针(继承)
【发布时间】:2021-08-11 08:57:02
【问题描述】:

我想将扩展的 Struct/Pointer(在下面的示例中 PY_LayerExtended)从 Python 发送到 C++,但出现错误。

我的 C++ 代码应该是这样的:

typedef struct PY_LayerBase {
} PY_LayerBase;


typedef struct PY_LayerExtended : PY_LayerBase {
} PY_LayerExtended;


typedef struct PY_Layer {
    PY_LayerBase* layerBase;
} PY_Layer;


// My Method
void parseTest(PY_Layer *py_layer) {

    // I cast PY_LayerBase to PY_LayerExtended
    PY_LayerExtended* py_layerExt = static_cast<PY_LayerExtended*>(py_layer->layerBase);

}

我的 Python 代码如下所示:

import ctypes
from ctypes import *

class PY_LayerBase (ctypes.Structure):
    _fields_ = []


class PY_LayerExtended (PY_LayerBase):
    _fields_ = []


class PY_Layer(ctypes.Structure):
    _fields_ = [("layerBase", PY_LayerBase)]


my_lib = cdll.LoadLibrary('mylib.dll')

py_layer_ext = PY_LayerExtended()
py_layer = PY_Layer(pointer(py_layer_ext))

parseTest = my_lib.parseTest
parseTest.argtypes = (POINTER(PY_Layer))

# Run C++
my_ptr = parseTest(pointer(py_layer))

当我运行 Python 时出现错误:

TypeError:不兼容的类型,PY_LayerExtended 实例而不是 PY_LayerBase 实例

错误发生在一行:py_layer = PY_Layer(pointer(py_layer_ext))

【问题讨论】:

    标签: python c++ ctypes


    【解决方案1】:

    ctypes 不理解 C++ 继承,即使您可以使用 Python 继承类似地声明 ctypes 结构。

    您可以通过以下两种方式之一来解决问题。下面我调整了 C++ 代码,以提供一些正确访问结构的反馈:

    test.cpp:

    #ifdef _WIN32
    #   define API __declspec(dllexport)
    #else
    #   define API
    #endif
    
    typedef struct PY_LayerBase {
        int a; // add element
    } PY_LayerBase;
    
    typedef struct PY_LayerExtended : PY_LayerBase {
        int b;  // also here, if cast works properly we'll return this value
    } PY_LayerExtended;
    
    typedef struct PY_Layer {
        PY_LayerBase* layerBase;
    } PY_Layer;
    
    extern "C" API
    int parseTest(PY_Layer *py_layer) {
        PY_LayerExtended* py_layerExt = static_cast<PY_LayerExtended*>(py_layer->layerBase);
        return py_layerExt->b;
    }
    

    选项 1:将指针转换为所需的类型:

    from ctypes import *
    
    class PY_LayerBase (Structure):
        _fields_ = ('a',c_int),
        def __init__(self,a):
            self.a = a
    
    class PY_LayerExtended(PY_LayerBase): # using Python inheritance to mimic C++ inheritance
        _fields_ = ('b',c_int),
        def __init__(self,a,b):
            super().__init__(a)
            self.b = b
     
    class PY_Layer(Structure):
        _fields_ = ("layerBase", POINTER(PY_LayerBase)), # Was missing POINTER
    
    my_lib = cdll.LoadLibrary('./test')
    
    py_layer_ext = PY_LayerExtended(5,7)
    py_layer = PY_Layer(cast(pointer(py_layer_ext),POINTER(PY_LayerBase))) # cast to required type
    
    parseTest = my_lib.parseTest
    parseTest.argtypes = POINTER(PY_Layer),
    parseTest.restype = c_int
    
    # Run C++
    print(parseTest(pointer(py_layer)))
    

    选项 2:像在纯 C 中一样在 Python 中声明结构,并传递一个指向基本结构的指针。这将具有与仅使用 C 数据类型的基类相同的布局。

    from ctypes import *
    
    class PY_LayerBase (Structure):
        _fields_ = ('a',c_int),
        def __init__(self,a):
            self.a = a
    
    class PY_LayerExtended(Structure):      # don't use inheritance,
        _fields_ = (('base',PY_LayerBase),  # make base structure a member
                    ('b',c_int))
        def __init__(self,a,b):
            self.base.a = a
            self.b = b
     
    class PY_Layer(Structure):
        _fields_ = ("layerBase", POINTER(PY_LayerBase)),
    
    my_lib = cdll.LoadLibrary('./test')
    
    py_layer_ext = PY_LayerExtended(5,7)
    py_layer = PY_Layer(pointer(py_layer_ext.base)) # pass pointer to base
    
    parseTest = my_lib.parseTest
    parseTest.argtypes = POINTER(PY_Layer), # added comma to make this a sequence as required
    parseTest.restype = c_int
    
    # Run C++
    print(parseTest(pointer(py_layer)))
    

    输出(两个选项):

    7
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-03-26
      • 1970-01-01
      • 2010-12-13
      • 1970-01-01
      • 2011-05-24
      • 1970-01-01
      • 2013-06-13
      • 2013-03-22
      相关资源
      最近更新 更多