【问题标题】:Return Ruby's Fiddle::Pointer from C function从 C 函数返回 Ruby 的 Fiddle::Pointer
【发布时间】:2018-07-27 23:02:50
【问题描述】:

我目前正在开发一个高性能的 Vector/Matrix Ruby gem C 扩展,因为我发现内置的实现很麻烦,对于我个人遇到的大多数情况并不理想,并且在其他领域也缺乏。

我的第一个方法是在 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 中做到这一点吗? Fiddle 不是核心库的一部分,它是标准库的一部分,因此实际上只是一个扩展本身。

这个问题很简单,可以通过上面演示的几行 Ruby 代码轻松解决,但如果没有 hack 的 C 扩展甚至可以返回 Fiddle 对象,那就更好奇了?我找不到任何这样做的例子,而且在涉及 Fiddle 的文档中,它一如既往地非常基础,没有太多解释。

【问题讨论】:

    标签: ruby rubygems ffi fiddle


    【解决方案1】:

    这个解决方案实际上相当简单,尽管我承认它没有我希望发现的优雅或干净的解决方案。

    可能有更复杂的方法来解决这个问题,包括 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 方法后,您可以调用它以获取指向内存中内部结构的大小指针。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-05
      • 2016-08-28
      • 1970-01-01
      • 2012-07-19
      • 2015-01-20
      • 1970-01-01
      相关资源
      最近更新 更多