3

我需要一些建议如何将 C/C++ 结构绑定到 Ruby。我已经阅读了一些手册,并且发现了如何将类方法绑定到类,但我仍然不明白如何绑定结构字段并使它们在 Ruby 中可访问。

这是我正在使用的代码:

myclass = rb_define_class("Myclass", 0);
...
typedef struct nya
{
    char const* name;
    int age;
} Nya;
Nya* p;
VALUE vnya;
p = (Nya*)(ALLOC(Nya));
p->name = "Masha";
p->age = 24;
vnya = Data_Wrap_Struct(myclass, 0, free, p);
rb_eval_string("def foo( a ) p a end"); // This function should print structure object
rb_funcall(0, rb_intern("foo"), 1, vnya); //  Here I call the function and pass the object into it

Ruby 函数似乎假定这a是一个指针。它打印指针的数值而不是它的真实内容(即["Masha", 24])。显然,Ruby 函数无法识别这个对象——我没有设置对象的属性名称和类型。

我怎样才能做到这一点?不幸的是,我无法弄清楚。

4

3 回答 3

3

您已经将指针包装在 Ruby 对象中。现在您所要做的就是定义如何从 Ruby 世界访问它:

/* Feel free to convert this function to a macro */
static Nya * get_nya_from(VALUE value) {
    Nya * pointer = 0;
    Data_Get_Struct(value, Nya, pointer);
    return pointer;
}

VALUE nya_get_name(VALUE self) {
    return rb_str_new_cstr(get_nya_from(self)->name);
}

VALUE nya_set_name(VALUE self, VALUE name) {
    /* StringValueCStr returns a null-terminated string. I'm not sure if
       it will be freed when the name gets swept by the GC, so maybe you
       should create a copy of the string and store that instead. */
    get_nya_from(self)->name = StringValueCStr(name);
    return name;
}

VALUE nya_get_age(VALUE self) {
    return INT2FIX(get_nya_from(self)->age);
}

VALUE nya_set_age(VALUE self, VALUE age) {
    get_nya_from(self)->age = FIX2INT(age);
    return age;
}

void init_Myclass() {
    /* Associate these functions with Ruby methods. */
    rb_define_method(myclass, "name",  nya_get_name, 0);
    rb_define_method(myclass, "name=", nya_set_name, 1);
    rb_define_method(myclass, "age",   nya_get_age,  0);
    rb_define_method(myclass, "age=",  nya_set_age,  1);
}

现在您可以访问结构中保存的数据,您可以简单地在 Ruby 中定义高级方法:

class Myclass
  def to_a
    [name, age]
  end

  alias to_ary to_a

  def to_s
    to_a.join ', '
  end

  def inspect
    to_a.inspect
  end
end

供参考:README.EXT

于 2012-02-24T15:30:12.853 回答
1

这不是您关于结构的问题的直接答案,但它是解决将 C++ 类移植到 Ruby 的问题的一般解决方案。

您可以使用SWIG来包装 C/C++ 类、结构和函数。在结构的情况下,它是在烧房子来煎鸡蛋。但是,如果您需要一个工具将 C++ 类快速转换为 Ruby(和 20 种其他语言),SWIG 可能对您有用。

在涉及结构的情况下,您只需要创建一个包含(在最简单的情况下)行的 .i 文件#include <your C++ library.h>

PS再一次,这不是对涉及这个结构的问题的直接回答,但也许您可以使用更通用的解决方案,在这种情况下,这可能会对您有所帮助。

于 2012-02-24T11:33:15.510 回答
0

另一种选择是使用RubyInline - 它对转换 C 和 Ruby 类型(例如 int、char * 和 float)的支持有限,并且还支持访问 C 结构 - 请参阅APIaccessor中的方法。

于 2012-03-09T14:16:14.330 回答