返回Ruby';来自C函数的指针
我目前正在开发一个高性能的Vector/Matrix Ruby gem C扩展,因为我发现内置的实现很麻烦,对于我个人遇到的大多数情况都不理想,而且在其他方面也不理想 我的第一种方法是在Ruby中实现为返回Ruby';来自C函数的指针,ruby,rubygems,ffi,fiddle,Ruby,Rubygems,Ffi,Fiddle,我目前正在开发一个高性能的Vector/Matrix Ruby gem C扩展,因为我发现内置的实现很麻烦,对于我个人遇到的大多数情况都不理想,而且在其他方面也不理想 我的第一种方法是在Ruby中实现为Fiddle::CStructEntity的一个子类,目标是使它们在不需要转换(例如传递到本机OpenGL函数)的情况下进行互操作优化。用C实现对数学有很大的好处,但我在尝试实现一个小函数时遇到了障碍 我希望有一个方法将Fiddle::Pointer返回到结构(基本上是一个指向Rdata->dat
Fiddle::CStructEntity
的一个子类,目标是使它们在不需要转换(例如传递到本机OpenGL函数)的情况下进行互操作优化。用C实现对数学有很大的好处,但我在尝试实现一个小函数时遇到了障碍
我希望有一个方法将Fiddle::Pointer
返回到结构(基本上是一个指向Rdata->data
的指针。我希望返回一个实际的Fiddle::pointer
对象。返回一个整数地址、压缩字符串等非常简单,使用它可以很容易地在Ruby方法中扩展以转换为Fiddle::pointer
:
def ptr
# Assume address is an integer address returned from C
Fiddle::Pointer.new(self.address, self.size)
end
这就向我提出了一个问题,甚至可以从C中这样做吗?Fiddle不是核心库的一部分,它是标准库的一部分,因此,它实际上只是一个扩展本身
这个问题很简单,可以通过上面演示的几行Ruby代码轻松解决,但更奇怪的是,如果从C扩展返回
Fiddle
对象而不需要黑客的话,是否还可以呢?我找不到任何这样做的例子,而且当涉及到Fiddle的文档时,总是这样这个问题的解决方案其实相当简单,尽管不象我希望发现的那样优雅或干净
可能有更详细的方法来实现这一点,包括Fiddle
的标题,并以此为基础进行构建,但这并不是一个真正可行的解决方案,因为我不想限制我的C扩展只与Ruby 2.0+一起工作,如果Ruby版本低于2.0
首先我包括version.h
,它允许访问定义宏RUBY\u API\u version\u MAJOR
,这是我真正需要知道的关于Fiddle
是否会出现的所有信息
这将是一个简化版本,简单地展示如何将Fiddle::Pointer
类作为值
,以及如何创建实例
#if RUBY_API_VERSION_MAJOR >= 2
rb_require("fiddle");
VALUE fiddle = rb_const_get(rb_cObject, rb_intern("Fiddle"));
rb_cFiddlePointer = rb_const_get(fiddle, rb_intern("Pointer"));
#endif
在本例中,该类存储在rb_cFiddlePointer
中,然后可以使用它从C创建并返回Fiddle::Pointer
对象
// Get basic data about the struct
struct RData *rdata = RDATA(self);
VALUE *args = xmalloc(sizeof(VALUE) * 2);
// Set the platform pointer-size address (could just use size_t here...)
#if SIZEOF_INTPTR_T == 4
args[0] = LONG2NUM((long) rdata->data);
#elif SIZEOF_INTPTR_T == 8
args[0] = LL2NUM((long long) rdata->data);
#else
args[0] = INT2NUM(0);
#endif
// Get size of structure
args[1] = INT2NUM(SIZE_OF_YOUR_STRUCTURE);
VALUE ptr = rb_class_new_instance(2, args, rb_cFiddlePointer);
xfree(args);
return ptr;
将函数链接到实际的Ruby方法后,可以调用它以获得指向内存中内部结构的大小指针