来自 C 函数的 Return Ruby 的 Fiddle::Pointer

Return Ruby's Fiddle::Pointer from C function

我目前正在开发一个高性能的 Vector/Matrix Ruby gem C 扩展,因为我发现内置的实现很麻烦,而且对于我拥有的大多数情况来说并不理想亲身遇到过,还有其他方面欠缺的。

我的第一个方法是在 Ruby 中实现为 Fiddle::CStructEntity 的子类,目标是使它们针对互操作进行优化,而无需转换(例如传递给本机 OpenGL 函数)。用 C 实现对数学有很大好处,但我 运行 在尝试实现次要函数时遇到了障碍。

我希望有一个方法 return 一个 Fiddle::Pointer 到结构(基本上是一个指向 Rdata->data 的指针。我希望 return 一个实际的 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 代码轻松解决,但更好奇的是 returning 一个 Fiddle 对象是否是偶数可以从没有黑客的 C 扩展中获得吗?我无法找到任何这样做的例子,并且一如既往地涉及涉及 Fiddle 的文档,它非常基础,没有太多解释。

这个解决方案实际上相当简单,尽管诚然它不像我希望发现的那样优雅或干净。

通过为 Fiddle 添加 headers 并针对它构建,可能有更精细的方法来解决这个问题,但这并不是一个真正可行的解决方案,因为我不想要将我的 C 扩展限制为仅适用于 Ruby 2.0+,并且在 Ruby 版本低于 2.0.

时简单地省略该方法是完全可以接受的

首先我包含了 version.h,它提供了定义宏 RUBY_API_VERSION_MAJOR 的权限,这就是我真正需要知道的关于 Fiddle 是否存在的所有信息.

这将是一个简化版本,仅展示如何将 Fiddle::Pointer class 作为 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

在此示例中,class 存储在 rb_cFiddlePointer 中,然后可用于从 C 创建 return Fiddle::Pointer object .

    // 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 方法后,您可以调用它以获取指向内存中内部结构的大小指针。