ruby - 从 C 函数返回 Ruby 的 Fiddle::Pointer
问题描述
我目前正在开发一个高性能的 Vector/Matrix Ruby gem C 扩展,因为我发现内置实现很麻烦,并且对于我个人遇到的大多数情况并不理想,并且在其他领域也缺乏。
我的第一种方法是在 Ruby 中作为Fiddle::CStructEntity
. 在 C 中实现为数学提供了很大的好处,但是在尝试实现一个次要函数时遇到了障碍。
我希望有一个方法将 a 返回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 代码轻松解决,但如果Fiddle
没有 hack 甚至可以从 C 扩展返回一个对象,那就更好奇了?我找不到任何这样做的例子,并且一如既往地涉及涉及 Fiddle 的文档,它非常基本,并没有太多解释。
解决方案
这个解决方案实际上相当简单,尽管我承认它没有我希望发现的优雅或干净的解决方案。
可能有更复杂的方法来解决这个问题,包括头文件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
,然后可用于Fiddle::Pointer
从 C 创建和返回对象。
// 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 方法后,您可以调用它来获取指向内存中内部结构的大小指针。
推荐阅读
- excel - 根据关键字列表将行移动到另一个工作表
- python - 如果使用 groupby 方法满足另一列中的条件,则使用多列有条件地过滤
- c# - 调用 API 函数“文件/下载”时出错
- javascript - 使用 Web Workers 的高效 1000Hz 时钟
- bash - git 的最终别名失败(__git_aliases 命令似乎已被弃用)
- c# - 在 C# 中使用哪个参考 - ConvertIdType
- php - 如何在不安装和使用 IP 地址访问的情况下运行 MySQL(如 http://127.0.0.1/phpmyadmin)
- assembly - VPERMILPS 指令 (_mm_permute_ps) 的意义何在?
- c - 用 C 处理多通道 wav 文件
- jupyter-notebook - 带有 Jupyter 的 Google Dataproc - 下载笔记本生成的文件