2015-11-04 52 views
1

我試圖包裝下面的函數來做C擴展。Ruby C擴展:將int函數轉化爲ruby值

int dsvd(float **a, int m, int n, float *w, float **v){ 
    //do some things 
} 

而且我有我的init,這是不完全正確:

void Init_svd() { 
    VALUE rb_mSvd = rb_define_module("Svd"); 
    rb_define_method(rb_mSvd, "svd", dsvd, 0); 
} 

我知道我需要包裝DSVD,這樣我可以通過一個Valuerb_define_method但我不能很圖走出正確的方式來做到這一點。我試圖修改this的答案,但無法弄清楚。有什麼建議麼?

編輯*我還閱讀了關於C擴展的實用程序員部分,但這主要關注對象的創建/分配。我試圖提供一個函數來執行一些轉換並返回一個值,所以我不能在概念上進行匹配。

回答

2

如果整數適合Fixnum,則可以使用宏INT2FIX爲dsvd()返回的整數返回一個Fixnum值。否則,你必須使用INT2NUM,它有一個函數調用開銷(它調用rb_int2inum)。有關更多詳細信息,請在ruby.h中查找這些宏。

編輯:您的評論表明您需要購買一個批次更多幫助。你想要這樣的東西。我沒有編譯這個,它沒有檢查論證的完整性,但它應該讓你去)。您的方法的簽名看起來像在數組a和v中傳遞的值可能會更改,並且此代碼不會將任何更改複製回Ruby版本(使用rb_ary_store來分配元素)。

#include  <ruby.h> 
    #include  <ruby/intern.h> 

    static VALUE rb_mSvd; 

    static VALUE 
    rb_svd(VALUE self, VALUE a_array, VALUE m_v, VALUE n_v, VALUE w_v, VALUE v_array) 
    { 
      /* Note that there is no checking here for correct types or sane values! */ 
      long a_len = RARRAY_LEN(a_array);     /* get the length of first (array) argument */ 
      float* a = (float*)malloc(sizeof(float)*a_len);  /* make space for the copies */ 
      int  m = NUM2INT(m_v); 
      int  n = NUM2INT(n_v); 
      float w = NUM2DBL(w_v); 
      long v_len = RARRAY_LEN(v_array); 
      float* v = (float*)malloc(sizeof(float)*v_len); 
      int  result; 

      for (int i = 0; i < a_len; i++) 
        a[i] = NUM2DBL(rb_ary_entry(a_array, i)); 

      for (int i = 0; i < v_len; i++) 
        v[i] = NUM2DBL(rb_ary_entry(v_array, i)); 

      result = dsvd(&a, m, n, w, &v); 

      free(a); 
      free(v); 
      return INT2NUM(result); 
    }    

    void Init_svd() 
    { 
      rb_mSvd = rb_define_module("Svd"); 
      rb_define_method(rb_mSvd, "svd", rb_svd, 5); 
    } 
+0

所以我會做類似'VALUE rb_svd(VALUE自我,VALUE **一,值m n值,值* W,VALUE ** V){}'或者我應該展開的ARGS? –

+0

太棒了!謝謝,這似乎是要做的伎倆。 –