从C到Ruby获取char* 和size_t,并在不使用FFI的情况下将它们从Ruby传递到C(使用SWIG)

ttp71kqs  于 9个月前  发布在  Ruby
关注(0)|答案(1)|浏览(59)

我有个问题因为我没办法了。我有一个用SWIG Package 的C库。我不使用FFI,因为我不想在我的GEM中有任何第三方依赖。问题是我遇到了一些问题。我在C中有一个函数,它创建char* buffer并返回它的大小。我需要返回ruby的缓冲区大小和缓冲区本身。使用size_t不是大问题,我可以在ruby端将其存储为int,并在返回C后对其进行强制转换,但我对char* 有问题。
当我把char* 从C返回到ruby时,它被转换为字符串。所以我不能再把它作为char* 返回给C。我试图做一些肮脏的事情,比如获取char* 的内存地址,将其存储为字符串并将其传递回C,但也不起作用。
什么是用例我需要使用第三方c库链接两个ruby线程。因此,我需要在线程1上创建链接示例,并将char* 和size_t指针传递给线程2,这是一个初始化链接。因此,没有改变这种做法的选择。
问题是,是否可以将引用传递给char* 指针C -> Ruby -> C以及如何做到这一点。我挖的解决方案,因为2天,但我没有好主意在这里。
Thx in advance:)
将char* 从C返回到Ruby的示例函数

char* link_rb() {
    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);
        }
    
    return in_process_link;
}

link_create不是我的函数,我需要在这里使用它(不能更改它)。
另一方面,我需要做这样的事情:

tracer_handle_t tracer_create_rb(unsigned char const* link) {
    size_t link_size = 40;

    char* buffer = (char*) &link;
    
    size_t tracer = inprocesslinktracer_create(link, link_size);
    return tracer;
}

inprocesslinktracer_create也不是我的函数。来自SDK
让我们假设现在我只返回char*,并传递它以及单个参数。一般来说,我需要缓冲区的大小,我可以在这里进入结构,但首先我想在这里弄清楚。

bt1cpqcv

bt1cpqcv1#

问题是,是否可以将引用传递给char* 指针C -> Ruby -> C
是的
SWIG默认假设char *类型的对象应该被 Package ,以便给予访问指向的数据的权限,而不是指针本身。这与它处理其他指针的方式不同。但是,SWIG的Map行为可以通过Typemaps进行定制,并且在必要的时候,您可以通过编写一个shim来帮助它(这里的示例不需要)。
示例代码可以使用简单的输入和输出类型Map:

mymodule.i

%module mymodule

/* Relying on SWIG to #include <ruby.h> */
%typemap(in) unsigned char const *AS_NUMBER {
    $1 = (unsigned char const *) NUM2ULL($input);
}
%typemap(out) char *link_rb {
    $result = ULL2NUM((unsigned long long) $1);
}

%{
#include "tracer.h"
%}

/*
 * We don't want SWIG to process all of tracer.h.  This is what we actually
 * want wrapped, and any additional declarations needed to fully define that.
 * These declarations need to be compatible with the those in tracer.h:
 */
#include <stddef.h>
typedef size_t tracer_handle_t;

char *link_rb(void);
tracer_handle_t tracer_create_rb(unsigned char const *AS_NUMBER);

in类型Map为匹配给定名称和数据类型的参数或对象指定Ruby -> C转换。类似地,out类型Map为返回值或匹配给定名称和数据类型的对象指定了C -> Ruby转换。请注意,AS_NUMBER仅具有该接口文件赋予的意义。这对SWIG来说并不特别。
一般来说,我需要缓冲区的大小,我可以在这里进入结构,但首先我想在这里弄清楚。
随你便

相关问题