Python3.9调用C++ DLL遇Access Violation Writing错误求助
解决ctypes调用含std::vector的C++结构体时的访问违规问题
问题根源
你遇到的OSError: exception: access violation writing 0x000000000000错误,核心原因是C++结构体中的std::vector<int> toolptidx无法直接用Python的ctypes.POINTER(c_int)模拟。
std::vector不是单纯的指针,它内部包含三个核心成员(以MSVC为例):
- 指向数据起始的指针
- 指向当前数据末尾的指针
- 指向内存容量末尾的指针
C++函数调用时会尝试修改这些内部成员(比如push_back时更新_Mylast),但你用POINTER(c_int)只传递了一个空指针或单纯的数据指针,没有vector的完整结构,导致函数写入非法内存地址。
可行解决思路
1. 修改C++ DLL接口(最优方案)
如果能修改原DLL的代码,将std::vector替换为C兼容的结构:
struct T_ToolDataResult { // ... 其他成员不变 int* toolptidx; // 指向C数组的指针 int toolptidx_count; // 数组中元素的数量 int toolptidx_capacity; // 数组的容量(可选) T_ToolDataResult* next; };
同时修改MappingPointSetsForMarkerSpaceReg函数,新增参数接收数组容量,避免越界:
int MappingPointSetsForMarkerSpaceReg(Handle p, T_MarkerInfo & marker, T_ToolDataResult * plist, int minimumMatchPts, int toolptidx_capacity)
Python端对应修改结构体:
class T_ToolDataResult(ctypes.Structure): pass T_ToolDataResult._fields_ = [ # ... 其他成员不变 ('toolptidx', ctypes.POINTER(ctypes.c_int)), ('toolptidx_count', ctypes.c_int), ('toolptidx_capacity', ctypes.c_int), ('next', ctypes.POINTER(T_ToolDataResult)) ]
调用前预先分配数组并初始化:
toolptidx_buf = (ctypes.c_int * 200)() res = T_ToolDataResult() res.toolptidx = toolptidx_buf res.toolptidx_capacity = 200 res.toolptidx_count = 0 rlt = Lib.MappingPointSetsForMarkerSpaceReg(Handle, cpp.byref(markerSt), cpp.byref(res), 0, 200)
2. 封装中间C++ DLL(次优方案)
如果无法修改原DLL,编写一个中间DLL作为适配层:
- 中间DLL调用原DLL的
MappingPointSetsForMarkerSpaceReg函数 - 将返回的
T_ToolDataResult中的std::vector数据复制到C风格数组 - 对外暴露纯C兼容的接口给Python调用
3. 模拟std::vector内存结构(临时方案,依赖编译器)
如果必须直接调用原DLL,可以模拟目标编译器的std::vector结构(以MSVC为例):
首先定义模拟的vector结构体:
class VectorInt(ctypes.Structure): _fields_ = [ ("_Myfirst", ctypes.POINTER(ctypes.c_int)), ("_Mylast", ctypes.POINTER(ctypes.c_int)), ("_Myend", ctypes.POINTER(ctypes.c_int)) ]
修改T_ToolDataResult中的toolptidx类型:
class T_ToolDataResult(ctypes.Structure): pass T_ToolDataResult._fields_ = [ # ... 其他成员不变 ('toolptidx', VectorInt), ('next', ctypes.POINTER(T_ToolDataResult)) ]
调用前初始化vector的内存:
# 分配200个int的内存空间 buffer = (ctypes.c_int * 200)() vec = VectorInt() vec._Myfirst = buffer # 数据起始地址 vec._Mylast = buffer # 当前数据长度为0 vec._Myend = buffer + 200 # 内存容量为200 res = T_ToolDataResult() res.toolptidx = vec rlt = Lib.MappingPointSetsForMarkerSpaceReg(Handle, cpp.byref(markerSt), cpp.byref(res), 0)
注意:该方法仅适用于特定编译器(如MSVC),不同编译器的std::vector内存布局可能不同,移植性差。
内容的提问来源于stack exchange,提问作者hwztable
相关产品推荐
相关产品推荐

