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

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定义,发现关键差异:

  1. 结构体字段名不匹配:DLL头文件中PointCloud结构体的字段名为number_of_points,但CFFI的cdef中写的是nPoints,而Ctypes和官方演示代码用的是nPoints,这会导致结构体内存布局错位,DLL写入时访问错误内存地址。
  2. 不排除DLL更新后调整了内存对齐规则,CFFI默认对齐方式与MSVC编译的DLL不兼容。

修复步骤

  1. 修正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 )
        }
    )
    
  2. 显式指定内存对齐(可选)
    若DLL采用MSVC默认对齐,可在CFFI结构体定义中添加对齐属性,确保内存布局一致:

    typedef struct __attribute__((aligned(8))) {
        uint32_t number_of_points;
        PointXYZ * pointcloud;
    } PointCloud;
    
  3. 验证调用约定
    头文件中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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 11:12:02