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

在Python(SWIG)中如何将mmap转换为ctypes void**?

解决Python中mmap转void**适配SWIG封装C库的问题

核心逻辑对应

你的C代码核心是:通过mmap获取内存指针char* image_buf,再取该指针的地址作为void**赋值给trans.frame_buffers。在Python中需要复刻这个"指针的指针"的构造逻辑。


问题1:将mmap转换为指针

有两种可靠方式:

方式1:直接调用libc的mmap获取指针(推荐)

直接调用系统libc的mmap函数,能直接拿到底层指针,避免Python mmap模块的额外封装。注意要严格匹配C函数的参数类型:

import ctypes
import os
import mmap

# 加载libc并声明mmap的函数原型(必须,否则ctypes会自动转换参数导致错误)
libc = ctypes.CDLL("libc.so.6")
libc.mmap.argtypes = [
    ctypes.c_void_p,    # addr
    ctypes.c_size_t,    # length
    ctypes.c_int,       # prot
    ctypes.c_int,       # flags
    ctypes.c_int,       # fd
    ctypes.c_off_t      # offset
]
libc.mmap.restype = ctypes.c_void_p

# 打开设备文件
axidma_fd = os.open("/dev/axidma", os.O_RDWR | os.O_EXCL)
image_byte_size = 188

# 调用mmap获取void*指针
image_ptr = libc.mmap(
    0,
    image_byte_size,
    mmap.PROT_READ | mmap.PROT_WRITE,  # 注意用PROT_*常量,不是ACCESS_*
    mmap.MAP_SHARED,
    axidma_fd,
    0
)

方式2:从Python标准库mmap对象提取指针

如果已经使用了Python的mmap模块,可通过ctypes提取底层指针:

import mmap
import ctypes

axidma_fd = os.open("/dev/axidma", os.O_RDWR | os.O_EXCL)
image_byte_size = 188

# 创建Python mmap对象
image_buf_1 = mmap.mmap(
    axidma_fd,
    image_byte_size,
    mmap.MAP_SHARED,
    mmap.PROT_READ | mmap.PROT_WRITE
)

# 提取底层char*指针,再转换为void*
char_ptr = ctypes.c_char_p.from_buffer(image_buf_1)
image_ptr = ctypes.c_void_p(char_ptr.value)

问题2:构造void**类型

C中的(void**)&image_buf是取指针变量的地址,在Python中对应以下步骤:

  1. 把获取到的image_ptr存入一个ctypes.c_void_p类型的变量(对应C里的void*变量)
  2. 用ctypes.pointer()获取该变量的地址,得到的就是POINTER(c_void_p)类型,完全匹配C的void**

代码实现:

# 步骤1:创建存储指针的变量
frame_buf_ptr = ctypes.c_void_p(image_ptr)
# 步骤2:构造void**并赋值给trans.frame_buffers
trans.frame_buffers = ctypes.pointer(frame_buf_ptr)

效率对比:直接调用libc vs Python mmap

  • 直接调用libc.mmap效率略高:少了Python mmap模块的封装层,但性能差异极小,普通场景可忽略。
  • Python mmap模块优势:提供字节串式的操作接口,自动处理部分内存管理细节,更符合Python习惯。
  • 若仅为给SWIG封装的C库提供指针,直接调用libc.mmap更直接,避免额外转换步骤。

解决之前的错误问题

  1. c_void_p.from_buffer(mmap对象)得到None:from_buffer是读取缓冲区内容而非获取指针地址,正确方式是用from_buffer获取指向缓冲区的指针,再取其value属性。
  2. libc.mmap指针赋值报错:直接传入c_void_p是void*类型,而接口需要void**,必须先把指针存入变量再取其地址。
  3. byref/from_buffer类型不匹配:byref是临时引用对象,不是正式的POINTER类型;from_buffer得到的是void*,需要再封装一层指针的指针才能匹配void**。

内容的提问来源于stack exchange,提问作者jcc18

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 21:25:21