使用Fiddle将结构体传递给本地代码或从本地代码返回结构体是否可能?

21
我希望使用Fiddle来访问由Rust代码编译的本地库。该结构体的C表示非常简单,只有一个指针和一个长度:
typedef struct {
    char *data;
    size_t len;
} my_thing_t;

// Example function that somehow accepts a struct
void accepts_a_struct(my_thing_t thing);

// Example function that somehow returns a struct
my_thing_t returns_a_struct(void);

然而,我能找到的所有示例都接受或返回指向结构体的指针,而不是结构体本身。如果可能的话,我想尽量避免双重间接引用。
我从Fiddle::Importer文档中借鉴了一个示例。但是,我不知道如何正确地调用extern方法以使用结构体而不是指向结构体的指针。
require 'fiddle'
require 'fiddle/import'

module LibSum
  extend Fiddle::Importer
  dlload './libsum.so'
  extern 'double sum(double*, int)'
  extern 'double split(double)'
end

注意

Fiddle和FFI gem不同。 Fiddle是Ruby标准库的组件,不作为单独的gem提供。 这些相关问题涉及FFI gem,而不涉及Fiddle:


有趣的问题,但我怀疑这是不可能的,因为FFI(Fiddle的包装器)似乎不支持直接传递结构体,请参阅此文档中的“函数参数和返回值”部分(日语,我正在阅读谷歌的翻译),如果您期望获得一些性能提升,您很可能不会得到任何显着的东西 - Ruby的变量是指向具有数据(RBasic和子类)的结构体的指针,甚至从那里指向堆中实际数据的另一个指针。 - Eugene Petrov
函数签名中支持的类型列表也可以从parse_ctype函数中获取。 - Eugene Petrov
1个回答

12

我已经阅读过Fiddle文档,并且我发现这是不可能的,因为即使在核心函数定义Fiddle::Function.new中也需要参数,Fiddle::CParser可以处理它们。我进行了各种测试,为了使它起作用,我不得不将您的代码转换成以下形式:

test2.c

#include <stdio.h>
#include <stdlib.h>

typedef struct {
  char *data;
  char *more_data;
  size_t len;
} my_thing_t;

my_thing_t *returns_a_struct(void){
  my_thing_t *structure = malloc(sizeof(my_thing_t));
  structure->data = "test2";
  structure->more_data = "I am more data";
  structure->len = 5;
  return structure;
};

irb

require 'fiddle'
require 'fiddle/import'
module Testmd
  extend Fiddle::Importer
  dlload './test2.dll'
  RetStruct = struct ['char *data','char *more_data','size_t len']
  extern 'RetStruct* returns_a_struct(void)'
end
include Testmd
2.2.1 :013 >   res = Testmd::returns_a_struct(nil)
 => #<Fiddle::Pointer:0x00000000b12a10 ptr=0x00000000e066b0 size=0 free=0x00000000000000> 
2.2.1 :014 > s = RetStruct.new(res)
 => #<Testmd::RetStruct:0x00000000c3e9e8 @entity=#<Fiddle::CStructEntity:0x000000007f0ad0 ptr=0x00000000e066b0 size=24 free=0x00000000000000>> 
2.2.1 :015 > s.data.to_s
 => "test2" 
2.2.1 :016 > s.more_data.to_s
 => "I am more data" 
2.2.1 :017 > s.len
 => 5
我总结出来的是,Fiddle可以处理简单数据类型,但需要通过引用传递structunion类型。尽管如此,它仍然为这些类提供了包装器。此外,这些包装器是从Fiddle::Pointer继承而来的,这表明他们希望我们对这些数据类型使用指针。
如果您想获取更多详细信息或添加此功能,可以查看他们的git存储库

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接