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

如何通过SWIG实现C与Ruby间char*指针的双向传递?

问题解决:SWIG实现char*指针在C→Ruby→C的引用传递

核心结论

可以实现,关键是避免SWIG默认将char*转换为Ruby字符串,而是让指针以原生内存引用的形式在Ruby端存储,传回C时再恢复为指针。以下是三种可行方案,按推荐程度排序:


方案1:封装结构体传递(推荐,同时兼容缓冲区大小)

直接将指针和大小封装为C结构体,让SWIG自动包装为Ruby对象,既解决指针传递,也覆盖后续需要传递大小的需求:

步骤1:定义C结构体

typedef struct {
    unsigned char* ptr;
    size_t size;
} LinkBuffer;

步骤2:修改C端生成和接收函数

// 生成链接缓冲区并返回结构体
LinkBuffer link_rb() {
    LinkBuffer buf = {NULL, 0};
    link_create(NULL, 0, &buf.size);
    if (buf.size != 0) {
        buf.ptr = (unsigned char*)malloc(buf.size);
        if (buf.ptr != NULL)
            buf.size = link_create(buf.ptr, buf.size, NULL);
    }
    return buf;
}

// 接收结构体并创建追踪器
tracer_handle_t tracer_create_rb(LinkBuffer buf) {
    return inprocesslinktracer_create(buf.ptr, buf.size);
}

步骤3:SWIG接口文件声明结构体

typedef struct {
    unsigned char* ptr;
    size_t size;
} LinkBuffer;

// 导出上述两个函数
%include "your_c_file.c"

Ruby端使用

# 第一个线程生成缓冲区
buf = YourModule.link_rb
# 将buf传递到第二个线程
# 第二个线程创建追踪器
tracer = YourModule.tracer_create_rb(buf)
# 使用完后记得释放内存(需新增C函数free(buf.ptr))
YourModule free_link_buffer(buf.ptr)

方案2:使用SWIG%pointer_class自动封装指针

让SWIG为unsigned char*生成一个指针包装类,Ruby端直接持有该类实例传递:

步骤1:SWIG接口添加指针类声明

%pointer_class(unsigned char, UnsignedCharPtr);
%include "your_c_file.c"

步骤2:修改C端函数返回unsigned char*并输出大小

unsigned char* link_rb(size_t *out_size) {
    size_t in_process_link_size = 0;
    link_create(NULL, 0, &in_process_link_size);
    unsigned char* in_process_link = NULL;
    if (in_process_link_size != 0) {
        in_process_link = (unsigned char*)malloc(in_process_link_size);
        if (in_process_link != NULL)
            in_process_link_size = link_create(in_process_link, in_process_link_size, NULL);
    }
    *out_size = in_process_link_size;
    return in_process_link;
}

tracer_handle_t tracer_create_rb(unsigned char const* link, size_t link_size) {
    return inprocesslinktracer_create(link, link_size);
}

Ruby端使用

# 第一个线程获取指针和大小
size_ptr = YourModule::SizeT.new
ptr = YourModule.link_rb(size_ptr)
link_size = size_ptr.value
# 传递ptr和link_size到第二个线程
# 第二个线程调用
tracer = YourModule.tracer_create_rb(ptr, link_size)

方案3:自定义SWIG类型映射(手动管理指针地址)

通过类型映射将指针地址转为Ruby数值存储,传回时再恢复为指针,适合极简场景:

步骤1:SWIG接口添加类型映射

// 输出:将unsigned char*转为Ruby整数(内存地址)
%typemap(out) unsigned char* {
    $result = LONG2NUM((long)$1);
}

// 输入:将Ruby整数转为unsigned char*指针
%typemap(in) unsigned char const* {
    $1 = (unsigned char const*)NUM2LONG($input);
}

%include "your_c_file.c"

Ruby端使用

# 第一个线程获取指针地址
ptr_addr = YourModule.link_rb
# 传递ptr_addr到第二个线程
# 第二个线程调用
tracer = YourModule.tracer_create_rb(ptr_addr)

关键注意事项

  1. 内存管理:C端malloc分配的内存Ruby不会自动释放,必须新增C函数void free_link(unsigned char* ptr) { free(ptr); },在Ruby端使用完指针后主动调用释放。
  2. 线程安全:确保指针在传递过程中不会被提前释放,第二个线程使用时指针必须有效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 13:01:13