我目前正在开发高性能的Vector / Matrix Ruby gem C扩展,因为我发现内置的实现很麻烦,对于我个人遇到的大多数情况以及其他领域所欠缺的情况来说,并不是理想的选择。< / p>
我的第一种方法是在Ruby中作为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做到这一点?小提琴不是核心库的一部分,它是标准库的一部分,因此实际上只是扩展本身。
这个问题很简单,可以通过上面展示的几行Ruby代码轻松解决,但是更好奇是否可以通过C扩展名返回Fiddle
对象而没有黑客?我无法找到完成此操作的任何示例,而且与涉及Fiddle的文档一样,它总是很基础的,没有太多解释。
答案 0 :(得分:0)
该解决方案实际上很简单,尽管公认它不像我希望发现的那样优雅或干净。
通过包括Fiddle
的标头并针对它进行构建,可能还有更多精心设计的方法,但这并不是真正可行的解决方案,因为我不想将C扩展名限制为仅适用于Ruby 2.0+,并且在Ruby版本低于2.0的情况下,只要省略该方法,完全可以接受。
首先,我包含version.h
,它提供了访问权限,定义了宏RUBY_API_VERSION_MAJOR
,关于Fiddle
是否存在,这是我真正需要知道的全部。
这是一个缩写版本,仅显示如何将Fiddle::Pointer
类作为VALUE
并创建实例。
#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方法之后,可以调用它以获取指向内存中内部结构的大小指针。