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

如何通过Swig封装的C++函数传递并返回Python bytes对象?

解决Python bytes与Swig封装C++函数的交互问题

我来帮你搞定这个问题!你之前用void*没成功,核心原因有两个:一是Swig默认不知道怎么把Python的bytes转换成C的void*(反之亦然),二是void*只存了内存地址,完全没记录数据的长度,C根本没法正确处理这块数据,甚至还可能因为Python的内存回收导致悬空指针崩溃。

下面是完整的解决方案,一步步来:

1. 修改C++代码:添加数据长度管理

首先得让你的C++类同时保存数据指针和长度,还要处理内存释放,避免内存泄漏:

example.hpp

class MyTestClass {
public:
    // 修改set_data,传入数据指针和长度
    void set_data(const void* data, size_t len);
    // 修改get_data,通过输出参数返回长度,返回数据指针
    const void* get_data(size_t& len) const;
    // 析构函数释放内存
    ~MyTestClass();
private:
    void* data = nullptr;
    size_t data_len = 0;
};

example.cpp

#include "example.hpp"
#include <cstring>

void MyTestClass::set_data(const void* data, size_t len) {
    // 先释放旧数据
    if (this->data) {
        delete[] static_cast<char*>(this->data);
    }
    // 复制新数据到C++管理的内存里
    this->data_len = len;
    this->data = new char[len];
    std::memcpy(this->data, data, len);
}

const void* MyTestClass::get_data(size_t& len) const {
    len = this->data_len;
    return this->data;
}

MyTestClass::~MyTestClass() {
    // 析构时释放内存
    if (data) {
        delete[] static_cast<char*>(data);
    }
}

2. 编写Swig接口文件:添加类型转换规则

Swig需要你告诉它怎么在Python bytes和C++的指针+长度之间转换,我们通过typemap来实现:

example.i

%module example

%{
#include "example.hpp"
%}

// 处理Python bytes转C++的(const void*, size_t)输入参数
%typemap(in) (const void* data, size_t len) {
    // 检查输入是否是bytes类型
    if (!PyBytes_Check($input)) {
        PyErr_SetString(PyExc_TypeError, "参数必须是bytes对象");
        return NULL;
    }
    // 获取bytes的内容指针和长度
    $1 = PyBytes_AsString($input);
    $2 = PyBytes_Size($input);
}

// 处理get_data的输出参数len,把返回的指针转成Python bytes
%typemap(argout) size_t& len {
    // 从C++拿到数据和长度,生成Python bytes对象
    PyObject* result_bytes = PyBytes_FromStringAndSize(
        static_cast<const char*>($result), 
        $1
    );
    // 替换原返回值为bytes
    $result = result_bytes;
}

// 让Swig处理我们的类和函数
%include "example.hpp"

3. 编译并测试

编译步骤(以Linux为例)

  1. 生成Swig包装代码:
swig -python example.i
  1. 编译C++代码和包装代码:
# 替换成你的Python头文件路径,比如/usr/include/python3.8
g++ -c example.cpp example_wrap.cxx -I/usr/include/python3.x
  1. 生成共享库:
g++ -shared example.o example_wrap.o -o _example.so

Python测试代码

import example

# 创建实例
test_obj = example.MyTestClass()
# 传入bytes数据
test_data = b"Hello Swig! This is Python bytes."
test_obj.set_data(test_data)
# 获取返回的bytes
result = test_obj.get_data()
print(f"返回的数据:{result}")
print(f"数据是否一致:{result == test_data}")

为什么之前的void*方案不行?

  • 类型转换缺失:Swig没有默认的规则把Python bytes映射到void*,反之亦然,必须手动通过typemap定义转换逻辑。
  • 数据长度丢失:void*只记录内存地址,C++不知道要读取多少字节,也就没法正确还原成Python bytes。
  • 内存安全问题:如果直接存Python bytes的指针,一旦Python的垃圾回收机制回收了这块内存,C里的指针就变成悬空指针,访问会导致程序崩溃。我们现在的方案是把数据复制到C管理的内存里,彻底避免这个问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:35:35