从 C 获取 char* 和 size_t 到 ruby,然后将它们从 Ruby 传递到 C,无需 FFI(使用 SWIG)

问题描述 投票:0回答:1

我有疑问,因为我没有想法。我有用 SWIG 包装的 c 库。我不使用 FFI,因为我不想在我的 GEM 中存在任何第三方依赖项。问题是我遇到了一些问题。我在 C 中有一个函数,它创建 char* 缓冲区并返回它的大小。我需要返回缓冲区和缓冲区本身的 ruby 大小。对于 size_t 不是大问题,我可以将它作为 int 存储在 ruby 端,并稍后返回到 C 后将其转换,但我对 char* 有问题。

当我将 char* 从 C 返回到 ruby 时,它会转换为字符串。所以我不能再将它作为 char* 返回到 C。我试图做一些肮脏的事情,比如获取 char* 的内存地址,将其存储为字符串并将其传递回 C,但两者都不起作用。

什么是用例。我需要使用第 3 方 C 库链接两个 ruby 线程。因此,我需要在线程一上创建链接实例,并将 char* 和 size_t 指针传递给线程2,这是一个初始化链接。所以没有办法改变这种方法。

问题是,是否可以传递对 char* 指针 C -> Ruby -> C 的引用以及如何做到这一点。我两天以来一直在寻找解决方案,但我这里没有好的想法。

提前谢谢:)

将 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* 并传递它以及单个参数。一般来说,我还需要缓冲区的大小,我可以转到此处的结构,但首先我想在这里弄清楚它。

c ruby swig
1个回答
0
投票

问题是,是否可以传递对 char* 指针的引用 C -> Ruby -> C

是的。

SWIG 默认情况下假设应包装

char *
类型的对象,以便访问所指向的数据,而不是指针本身。这与它处理其他指针的方式不同。但是,SWIG 的映射行为可以通过 Typemaps 进行自定义,并且在必要时,您可以通过编写垫片来帮助它(所提供的示例不需要)。

示例代码可以使用简单的输入和输出类型映射来提供:

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
类型映射指定匹配给定名称和数据类型的参数或对象的 Ruby -> C 转换。类似地,
out
类型映射指定与给定名称和数据类型匹配的返回值或对象的 C -> Ruby 转换。请注意,
AS_NUMBER
仅具有该接口文件赋予它的意义。这对 SWIG 来说并不特别。

一般来说,我还需要缓冲区的大小,我可以转到此处的结构,但首先我想在这里弄清楚它。

随你喜欢。

© www.soinside.com 2019 - 2024. All rights reserved.