【问题标题】:Creating C structs using the RubyInline gem使用 RubyInline gem 创建 C 结构体
【发布时间】:2015-06-25 13:30:45
【问题描述】:

我有一个 Rails 应用程序需要显示 Monte Carlo sim 的结果,而且第一次,Ruby 的速度不足以满足我的需求。因此,我开始四处寻找是否可以用 C 重写我的模拟并在 Ruby 中使用这些结果,并且一些谷歌搜索发现了 RubyInline gem,以便轻松地直接在 Ruby 中编写更快的 C 代码。做一些简单的事情效果很好,例如,一些用 Ruby 和 C 编写的基本函数:

class FasterFunctions
  inline do |builder|
    builder.c '
    double rand_sum(int trials)
    {
      double sum = 0.0;
      for (int i = 0; i<trials; i++)
      {
        sum += (double)rand()/(double)RAND_MAX;
      }
      return sum;
    }'

    builder.c '
    long loop_sum(long trials)
    {
      long sum = 0;
      for (long i = 0; i<trials; i++)
      {
        sum+=i;
      }
      return sum;
    }'
  end
end

#the C version is 4 orders of magnitude faster
trials = 1_000_000
ruby_sum = 0
trials.times {|i| ruby_sum += i}
c_sum = FasterRand.new.loop_sum(trials)

# the C version is 1 order of magnitude faster
ruby_sum = 0.0
trials.times {ruby_sum += rand}
c_sum = FasterRand.new.rand_sum(trials)

所以,太好了,它肯定会加快我的模拟速度,因为它几乎只是生成随机数并根据这些结果添加东西。不幸的是,除了像这样的基本内容之外,我无法弄清楚如何实际编写我的程序。我需要传递一些结构来充当状态变量,因此首要任务是弄清楚如何创建 C 结构。看了the documentation,感觉应该挺简单的。

访问器(方法、类型、成员 = 方法)

为通过包装的 C 结构成员添加读取器和写入器 Data_Wrap_Struct。方法是赋予访问者的红宝石名称,类型 是C型。除非 C 成员名称被 member 覆盖,否则 方法名用作结构成员。

builder.struct_name = 'MyStruct' 
builder.accessor :title,        'char *' 
builder.accessor :stream_index, 'int',   :index

文档对我来说并不完全清楚,但我认为我会像以前一样将它放在一个类中并执行以下操作来访问它:

class MyStructClass
  inline do |builder|
    builder.struct_name = 'MyStruct'
    builder.accessor :title, 'char *'
    builder.accessor :stream_index, 'int', :index
  end
end

#possible this
struct = MyStructClass.new.MyStruct
struct.title = 'A Title'

#or maybe
struct = MyStructClass.new
struct.title = 'A Title'

不幸的是,我什至无法做到这一点

*/.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:3: 错误:使用未声明的标识符 'MyStruct' 我的结构 * 指针; ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:13:错误:使用未声明的标识符 '指针' MyStruct *指针; ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:458:35:错误:使用未声明的标识符 '指针' Data_Get_Struct(self, MyStruct, 指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6:注意:从宏“Data_Get_Struct”扩展 (sval) = (type)DATA_PTR(obj);\ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:458:25:错误:使用未声明的标识符 'MyStruct' Data_Get_Struct(self, MyStruct, 指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:15:注意:从宏“Data_Get_Struct”扩展 (sval) = (type)DATA_PTR(obj);\ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:458:3: 错误:预期表达式 Data_Get_Struct(self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:20:注意:从宏“Data_Get_Struct”扩展 (sval) = (type)DATA_PTR(obj);\ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:460:23:错误:使用未声明的标识符 “指针”返回(rb_str_new2(指针->标题)); ^ */.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/intern.h:786:27:注意:从宏“rb_str_new_cstr”扩展 (__builtin_constant_p(str)) ? \ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:460:23:错误:使用未声明的标识符 '指针' */.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/intern.h:787:14:注意:从宏“rb_str_new_cstr”扩展 rb_str_new((str), (long)strlen(str)) : \ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:460:23:错误:使用未声明的标识符 '指针' */.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/intern.h:787:33:注意:从宏“rb_str_new_cstr”扩展 rb_str_new((str), (long)strlen(str)) : \ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:460:23:错误:使用未声明的标识符 '指针' */.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/intern.h:788:18:注意:从宏“rb_str_new_cstr”扩展 rb_str_new_cstr(str); \ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:460:10:错误:从 具有不兼容结果类型'VALUE'(又名'unsigned long')的函数返回(rb_str_new2(pointer->title)); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:478:3: 错误:使用未声明的标识符 'MyStruct' 我的结构 * 指针; ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:478:13:错误:使用未声明的标识符 '指针' MyStruct *指针; ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:480:35:错误:使用未声明的标识符 '指针' Data_Get_Struct(self, MyStruct, 指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6:注意:从宏“Data_Get_Struct”扩展 (sval) = (type)DATA_PTR(obj);\ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:480:25:错误:使用未声明的标识符 'MyStruct' Data_Get_Struct(self, MyStruct, 指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:15:注意:从宏“Data_Get_Struct”扩展 (sval) = (type)DATA_PTR(obj);\ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:480:3: 错误:预期表达式 Data_Get_Struct(self, MyStruct, pointer); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:20:注意:从宏“Data_Get_Struct”扩展 (sval) = (type)DATA_PTR(obj);\ ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:482:3: 错误:使用未声明的标识符 'pointer' 指针->title = StringValuePtr(value); ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:3: 错误:使用未声明的标识符 'MyStruct' 我的结构 * 指针; ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:456:13:错误:使用未声明的标识符 '指针' MyStruct *指针; ^ */.rbenv/versions/2.1.2/lib/ruby/gems/2.1.0/gems/RubyInline-3.12.4/lib/inline.rb:458:35:错误:使用未声明的标识符 '指针' Data_Get_Struct(self, MyStruct, 指针); ^ /.rbenv/versions/2.1.2/include/ruby-2.1.0/ruby/ruby.h:1038:6:注意:从宏“Data_Get_Struct”扩展 (sval) = (type)DATA_PTR(obj);\ ^ 致命错误:发出的错误太多,现在停止 [-ferror-limit=]

我已经进行了大量的谷歌搜索,但我发现的几乎每个示例都只涉及我最初概述的简单用例。它吐出的第一个错误是 MyStruct 未声明,所以我尝试在访问器方法之前添加一个结构定义,如下所示:

builder.c '
  typedef struct
  {
    char *title;
    int index;
  } MyStruct;
'

这没有任何作用,并且文档似乎很清楚 c 方法仅用于声明函数,而不是结构。我不确定接下来要尝试什么,有其他人有这方面的经验吗?

【问题讨论】:

    标签: c ruby


    【解决方案1】:

    RubyInline 似乎假设您知道编写 Ruby 扩展的方法,如果您正在做比基础更复杂的事情。

    确实需要在尝试时自己定义结构,但您应该使用prefix method 而不是c method(用于定义方法)。您还需要为该类定义分配方法。您可以通过添加一个名为allocate 的函数来使用c_singleton method 来执行此操作,RubyInline 将识别该函数并将其用作分配函数(这似乎没有记录,我通过查看源代码找到了它)。

    把它们放在一起看起来像这样。

    class Foo
      inline do |builder|
    
        # First define the struct that will be wrapped in the
        # class.
        builder.prefix <<-DEFINE_STRUCT
          typedef struct {
            char* bar;
          } MyStruct;
        DEFINE_STRUCT
    
        # Next define the allocation function that will
        # allocate and wrap a MyStruct struct when creating a
        # new Foo object. You might want to initialize the values
        # to avoid possible segfaults.
        builder.c_singleton <<-ALLOCATE
          VALUE allocate() {
            MyStruct* pointer = ALLOC(MyStruct);
            return Data_Wrap_Struct(self, NULL, free, pointer);
          }
        ALLOCATE
    
        # Finally we can use the struct_name and accessor methods.
        builder.struct_name = 'MyStruct'
        builder.accessor 'bar', 'char *' 
      end
    
    end
    

    请注意,如果您在主目录中的目录.ruby_inline 下查看,您可以看到生成的 C 代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-16
      • 2021-04-30
      相关资源
      最近更新 更多