2012-02-24 46 views
3

我需要一些建議如何將C/C++結構綁定到Ruby。我已經閱讀了一些手冊,並且發現瞭如何將類方法綁定到類,但是我仍然不明白如何綁定結構字段並使它們在Ruby中可訪問。如何將C/C++結構綁定到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函數不能識別這個對象—我沒有設置對象的屬性名稱和類型。

我該怎麼做?不幸的是我無法弄清楚。

+0

不是一個答案,但你有沒有考慮使用http://www.swig.org/,它會自動爲你生成這個接口代碼。 – jupp0r 2012-02-24 11:38:42

+0

'rb_funcall(0,rb_intern(「p」),1,vnya)''應該也能工作;-) – Reactormonk 2012-02-24 14:31:39

回答

1

這不是您對結構問題的直接回答,但它是將C++類移植到Ruby的一般解決方案。

您可以使用SWIG來打包C/C++類,結構和函數。在一個結構的情況下,它燒房子來炒雞蛋。但是,如果您需要一種工具將C++類快速轉換爲Ruby(以及20種其他語言),那麼SWIG可能對您有用。

在涉及結構的情況下,您只需創建一個包含(最簡單情況下)行#include <your C++ library.h>的.i文件。

P.S.再一次,這不是對涉及這個結構的問題的直接回答,但也許你可以使用更通用的解決方案,在這種情況下,這可能對你有幫助。

+0

「它燒房子來炒雞蛋」這是一個守護者 – 2012-07-03 15:49:49

+1

有時候一個人的房子裏裝滿了雞蛋.. 。 – MajesticRa 2012-07-03 19:35:32

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

0

另一種選擇是使用RubyInline - 它限制了支持用於將C和紅寶石類型(如int,char *與懸空),它也具有用於訪問C structurs支持 - 見在API中的方法。

相關問題