Ruby C扩展:将int函数转换为ruby值

时间:2021-09-13 02:39:05

I'm trying to wrap the following function to make a C extension.

我正在尝试包装以下函数来进行C扩展。

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

And I have my init, which isn't quite right:

我有我的初学者,这是不对的:

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

I know I need to wrap dsvd so that I can pass a Value to rb_define_method but I can't quite figure out the right way to do it. I tried adapting this answer, but couldn't quite figure it out. Any suggestions?

我知道我需要包装dsvd,以便我可以将值传递给rb_define_method,但我无法找到正确的方法来做到这一点。我试着调整这个答案,但还是没弄清楚。有什么建议么?

edit* I also read the Pragmatic Programmer section on C extensions, but that's focused on object creation/allocation. I'm trying to provide a function that performs some transformations and returns a value, so i couldn't make that match up conceptually.

编辑*我还阅读了关于C扩展的Pragmatic Programmer部分,但是它主要关注对象创建/分配。我正在尝试提供一个执行某些转换并返回值的函数,所以我无法在概念上进行匹配。

1 个解决方案

#1


2  

If the integer will fit into a Fixnum, you can use the macro INT2FIX to return a Fixnum value for the integer returned by dsvd(). Otherwise you have to use INT2NUM, which has a function-call overhead (it calls rb_int2inum). Look for these macros in ruby.h for more details.

如果整数适合Fixnum,则可以使用宏INT2FIX返回dsvd()返回的整数的Fixnum值。否则你必须使用INT2NUM,它具有函数调用开销(它调用rb_int2inum)。在ruby.h中查找这些宏以获取更多详细信息。

Edited: Your comment indicates you need a lot more help. You want something like this. I have not compiled this, and it has no checking for argument sanity, but it should get you going). The signature of your method looks like the values passed in the arrays a and v might be changed, and this code does not copy back any changes to the Ruby versions (use rb_ary_store to assign elements).

编辑:您的评论表明您需要更多帮助。你想要这样的东西。我没有编译这个,它没有检查参数的健全性,但它应该让你去)。您的方法的签名看起来像数组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);
    }

#1


2  

If the integer will fit into a Fixnum, you can use the macro INT2FIX to return a Fixnum value for the integer returned by dsvd(). Otherwise you have to use INT2NUM, which has a function-call overhead (it calls rb_int2inum). Look for these macros in ruby.h for more details.

如果整数适合Fixnum,则可以使用宏INT2FIX返回dsvd()返回的整数的Fixnum值。否则你必须使用INT2NUM,它具有函数调用开销(它调用rb_int2inum)。在ruby.h中查找这些宏以获取更多详细信息。

Edited: Your comment indicates you need a lot more help. You want something like this. I have not compiled this, and it has no checking for argument sanity, but it should get you going). The signature of your method looks like the values passed in the arrays a and v might be changed, and this code does not copy back any changes to the Ruby versions (use rb_ary_store to assign elements).

编辑:您的评论表明您需要更多帮助。你想要这样的东西。我没有编译这个,它没有检查参数的健全性,但它应该让你去)。您的方法的签名看起来像数组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);
    }