CFFI调用PointCloud.dll触发访问违例,Ctypes可正常运行求助
问题:CFFI调用更新后的PointCloud.dll触发访问违例,Ctypes实现正常运行
环境信息
- Windows 10(64位)
- Python版本:3.9(64位)、3.10(64位)
问题描述
实现了两种调用PointCloud.dll的方式,该DLL接收结构体缓冲区指针和缓冲区大小,返回点云数据。注:DLL写入点云缓冲区时仅参考传入的iBufSize参数,而非结构体中的nPoints变量。
CFFI实现运行时触发访问违例,退出码为-1073741819(0xC0000005),但相同逻辑的Ctypes实现可正常执行。两种实现在DLL旧版本下均能正常运行,DLL更新后对外接口未变但出现此问题。
相关代码片段
CFFI实现代码
from cffi import FFI ffi = FFI() lib = ffi.dlopen("PointCloud.dll") ffi.cdef( """ typedef struct { double x; double y; double z; } PointXYZ; typedef struct { uint32_t nPoints; PointXYZ * pointcloud; } PointCloud; int GetPointCloud(void * ptrPointCloudBuf, int iBufSize); """ ) nPts = 5000000 buf_size = nPts * ffi.sizeof('PointXYZ') pc_struct = ffi.new( "PointCloud *", { "nPoints": ffi.cast("uint32_t", 0), "pointcloud": ffi.new("PointXYZ []", nPts ) } ) retcode = lib.GetPointCloud(pc_struct, buf_size)
Ctypes实现代码
from ctypes import * lib = cdll.LoadLibrary("PointCloud.dll") class PointXYZ(Structure): _fields_ = [ ('x', c_double), ('y', c_double), ('z', c_double) ] class PointCloud(Structure): _fields_ = [ ('nPoints', c_uint32), ('pointcloud', POINTER(PointXYZ)), ] GetPointCloud = lib['GetPointCloud'] GetPointCloud.restype = c_int GetPointCloud.argtypes = [POINTER(PointCloud), c_int] nPts = 5000000 buf_size = nPts * sizeof(PointXYZ) pc_struct = pointer( PointCloud( nPoints=c_uint32(0), pointcloud=cast((PointXYZ * nPts)(), POINTER(PointXYZ)) ) ) retcode = lib.GetPointCloud(pc_struct, buf_size)
DLL头文件相关内容
#ifndef POINTCLOUD_H #define POINTCLOUD_H #if defined(_MSC_VER) #define POINTCLOUD_DLL_EXPORT __declspec(dllexport) #else #define POINTCLOUD_DLL_EXPORT __attribute__ ((visibility ("default"))) #define _stdcall #endif // Point structs typedef struct { double x; double y; double z; } PointXYZ; struct PointCloud { uint32_t number_of_points; PointXYZ * pointcloud; PointCloud() { pointcloud= nullptr; number_of_points = 0; } }; extern "C" POINTCLOUD_DLL_EXPORT int GetPointCloud(void* buffer, int buffer_size); #endif // POINTCLOUD_H
官方C/C++演示代码片段
struct PointXYZ { double x; double y; double z; }; struct PointCloud { uint32_t nPoints; PointXYZ * pointcloud; PointCloud() { pointcloud = nullptr; nPoints = 0; } }; PointCloud pcloud; int nPts = 5000000; pcloud.pointcloud = new PointXYZ[nPts]; buf_size = sizeof(PointXYZ) * nPts; int n = GetPointCloud(&pcloud, buf_size); if(n == 0) { printf("Success, result = %d\n", n); } else { printf("Failure, result = %d\n", n); } /* Do the rest with the point cloud. */
分析与修复方案
核心问题定位
对比两种实现与DLL定义,发现关键差异:
- 结构体字段名不匹配:DLL头文件中
PointCloud结构体的字段名为number_of_points,但CFFI的cdef中写的是nPoints,而Ctypes和官方演示代码用的是nPoints,这会导致结构体内存布局错位,DLL写入时访问错误内存地址。 - 不排除DLL更新后调整了内存对齐规则,CFFI默认对齐方式与MSVC编译的DLL不兼容。
修复步骤
修正CFFI结构体字段名
对齐DLL头文件的定义,修改CFFI的cdef部分:typedef struct { uint32_t number_of_points; PointXYZ * pointcloud; } PointCloud;同时调整结构体初始化的字段名:
pc_struct = ffi.new( "PointCloud *", { "number_of_points": ffi.cast("uint32_t", 0), "pointcloud": ffi.new("PointXYZ []", nPts ) } )显式指定内存对齐(可选)
若DLL采用MSVC默认对齐,可在CFFI结构体定义中添加对齐属性,确保内存布局一致:typedef struct __attribute__((aligned(8))) { uint32_t number_of_points; PointXYZ * pointcloud; } PointCloud;验证调用约定
头文件中MSVC环境未定义_stdcall,函数默认使用cdecl调用约定,CFFI和Ctypes默认均为cdecl,无需额外调整。
最终修正后的CFFI代码
from cffi import FFI ffi = FFI() lib = ffi.dlopen("PointCloud.dll") ffi.cdef( """ typedef struct { double x; double y; double z; } PointXYZ; typedef struct __attribute__((aligned(8))) { uint32_t number_of_points; PointXYZ * pointcloud; } PointCloud; int GetPointCloud(void * ptrPointCloudBuf, int iBufSize); """ ) nPts = 5000000 buf_size = nPts * ffi.sizeof('PointXYZ') pc_struct = ffi.new( "PointCloud *", { "number_of_points": ffi.cast("uint32_t", 0), "pointcloud": ffi.new("PointXYZ []", nPts ) } ) retcode = lib.GetPointCloud(pc_struct, buf_size)
内容的提问来源于stack exchange,提问作者Bawoo
相关产品推荐
相关产品推荐

