You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 18:07:02