Ctypes:扩展Struct/Pointer(继承)
Ctypes: Extended Struct/Pointer (Inheritance)
我想将 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))
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 数据类型的基础 class 具有相同的布局。
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
我想将 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))
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 数据类型的基础 class 具有相同的布局。
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