当我们使用 rb_funcall 时是否必须使用 rb_protect
Is the usage of rb_protect mandatory when we use rb_funcall
我已经开始为 clang-c 库编写 ruby 模块。
我将这个
包装在我的 clang c 模块中
unsigned clang_visitChildren(CXCursor parent,
CXCursorVisitor visitor,
CXClientData client_data);
遇到这样的访客:
typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor,
CXCursor parent,
CXClientData client_data);
ruby 代码(有效)如下所示:
Clangc.visit_children(cursor: tu.cursor) do |cursor, parent|
puts cursor
puts parent
Clangc::ChildVisitResult::RECURSE
end
思路是取块,作为参数传递给访问者,在访问者中调用。
C 胶代码如下所示:
VALUE
m_clangc_visit_children_with_proc(VALUE self, VALUE cursor, VALUE aproc)
{
if (rb_class_of(aproc) != rb_cProc) rb_raise(rb_eTypeError, "Need a block");
VALUE callback = aproc;
Cursor_t *c;
unsigned ret_with_break;
Data_Get_Struct(cursor, Cursor_t, c);
ret_with_break = clang_visitChildren(c->data,
visitor,
(CXClientData) callback);
/*return false if ret_with_break == 0*/
return NOT_0_2_RVAL(ret_with_break);
}
与访客(回调):
static enum CXChildVisitResult
visitor(CXCursor cursor, CXCursor parent, CXClientData client_data)
{
/*basic variables initialization...*/
r_ret = rb_funcall(callback, rb_intern("call"), 2, r_cursor, r_parent);
if (TYPE(r_ret) == T_FIXNUM)
{
ret = NUM2UINT(r_ret);
if (ret == CXChildVisit_Break || ret == CXChildVisit_Continue ||
ret == CXChildVisit_Recurse)
return ret;
else
return CXChildVisit_Break;
}
else
return CXChildVisit_Break;
}
我的回答是我应该在这里使用 rb_protect 吗?
代码可以在这里找到:
https://github.com/cedlemo/ruby-clangc/blob/master/ext/clangc/_clangc_functions.c#L146
经过一些测试和阅读其他人的代码后,我得出的结论是 rb_protect
封装 rb_funcall
的用法不是强制性的。
当你需要在 C 中处理由 rb_funcall
执行的 ruby 块或过程中可能出现的异常时,应该使用它。
我应该提一下,当你在 C 中嵌入 ruby 解释器时,处理这些异常肯定比你编写一些 C ruby 扩展时更重要。
参考资料:
git clone git://libvirt.org/ruby-libvirt.git
git clone https://github.com/ruby-gnome2/ruby-gnome2.git
http://clalance.blogspot.fr/2011/01/writing-ruby-extensions-in-c-part-5.html
我已经开始为 clang-c 库编写 ruby 模块。
我将这个
包装在我的 clang c 模块中unsigned clang_visitChildren(CXCursor parent,
CXCursorVisitor visitor,
CXClientData client_data);
遇到这样的访客:
typedef enum CXChildVisitResult (*CXCursorVisitor)(CXCursor cursor,
CXCursor parent,
CXClientData client_data);
ruby 代码(有效)如下所示:
Clangc.visit_children(cursor: tu.cursor) do |cursor, parent|
puts cursor
puts parent
Clangc::ChildVisitResult::RECURSE
end
思路是取块,作为参数传递给访问者,在访问者中调用。
C 胶代码如下所示:
VALUE
m_clangc_visit_children_with_proc(VALUE self, VALUE cursor, VALUE aproc)
{
if (rb_class_of(aproc) != rb_cProc) rb_raise(rb_eTypeError, "Need a block");
VALUE callback = aproc;
Cursor_t *c;
unsigned ret_with_break;
Data_Get_Struct(cursor, Cursor_t, c);
ret_with_break = clang_visitChildren(c->data,
visitor,
(CXClientData) callback);
/*return false if ret_with_break == 0*/
return NOT_0_2_RVAL(ret_with_break);
}
与访客(回调):
static enum CXChildVisitResult
visitor(CXCursor cursor, CXCursor parent, CXClientData client_data)
{
/*basic variables initialization...*/
r_ret = rb_funcall(callback, rb_intern("call"), 2, r_cursor, r_parent);
if (TYPE(r_ret) == T_FIXNUM)
{
ret = NUM2UINT(r_ret);
if (ret == CXChildVisit_Break || ret == CXChildVisit_Continue ||
ret == CXChildVisit_Recurse)
return ret;
else
return CXChildVisit_Break;
}
else
return CXChildVisit_Break;
}
我的回答是我应该在这里使用 rb_protect 吗?
代码可以在这里找到:
https://github.com/cedlemo/ruby-clangc/blob/master/ext/clangc/_clangc_functions.c#L146
经过一些测试和阅读其他人的代码后,我得出的结论是 rb_protect
封装 rb_funcall
的用法不是强制性的。
当你需要在 C 中处理由 rb_funcall
执行的 ruby 块或过程中可能出现的异常时,应该使用它。
我应该提一下,当你在 C 中嵌入 ruby 解释器时,处理这些异常肯定比你编写一些 C ruby 扩展时更重要。
参考资料:
git clone git://libvirt.org/ruby-libvirt.git
git clone https://github.com/ruby-gnome2/ruby-gnome2.git
http://clalance.blogspot.fr/2011/01/writing-ruby-extensions-in-c-part-5.html