2015-11-04 58 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

太棒了!谢谢,这似乎是要做的伎俩。 –