6

我想从我自己的 C 代码中调用 ruby​​ 代码。万一出现异常,我必须 rb_protect 我调用的 ruby​​ 代码。rb_protect 看起来像这样:

VALUE rb_protect(VALUE (* proc) (VALUE), VALUE data, int * state)

所以proc必须是一个接受VALUE参数并返回的函数VALUE。我必须调用很多不能以这种方式工作的函数。我怎样才能让rb_protect他们免于引发异常?

我曾想过使用Data_Make_Struct将所有内容包装到一个 ruby​​ 对象中并在其上调用方法。Data_Make_Struct本身可能引发异常。我该怎么做rb_protect Data_Make_Struct

4

1 回答 1

4

rb_protect以灵活的方式使用(例如,使用任意数量的参数调用 Ruby 函数),请将一个小的调度函数传递给rb_protect. Ruby 需要sizeof(VALUE) == sizeof(void*),并且rb_protect盲目地将VALUE-typed 数据传递给 dispatch 函数,而不检查或修改它。这意味着您可以将所需的任何数据传递给调度函数,让它解包数据并调用适当的 Ruby 方法。

例如,要rb_protect调用 Ruby 方法,您可能会使用如下内容:

#define MAX_ARGS 16
struct my_callback_stuff {
  VALUE obj;
  ID method_id;
  int nargs;
  VALUE args[MAX_ARGS];
};

VALUE my_callback_dispatch(VALUE rdata)
{
  struct my_callback_stuff* data = (struct my_callback_stuff*) rdata;
  return rb_funcall2(data->obj, data->method_id, data->nargs, data->args);
}

... in some other function ...
{
  /* need to call Ruby */
  struct my_callback_stuff stuff;
  stuff.obj = the_object_to_call;
  stuff.method_id = rb_intern("the_method_id");
  stuff.nargs = 3;
  stuff.args[0] = INT2FIX(1);
  stuff.args[1] = INT2FIX(2);
  stuff.args[2] = INT2FIX(3);

  int state = 0;
  VALUE ret = rb_protect(my_callback_dispatch, (VALUE)(&stuff), &state);
  if (state) {
    /* ... error processing happens here ... */
  }
}

另外,请记住,rb_rescue或者rb_ensure可能是解决某些问题的更好方法。

于 2013-02-27T06:43:22.437 回答