Rubyinline为RARRAY_LEN返回错误的结果

时间:2014-02-05 12:07:29

标签: c ruby

为什么这段代码在测试时会返回错误数量的元素?它似乎是正确值的一半

我使用的是RubyInline版本3.12.2。和Ruby 1.9.3

inline do|builder|
   builder.c <<-EOS
     VALUE arraylength( VALUE testarr){
       int arrlen = RARRAY_LEN(testarr);
       return arrlen;
     }
   EOS
end

结果是

arraylength([1,2,3,4,5])
#=>2

我期待

arraylength([1,2,3,4,5])
#=>5

1 个答案:

答案 0 :(得分:1)

代码的问题在于您已声明C函数返回VALUE(用于标识Ruby对象的长指针类型),但随后返回int。编译器可以在这里强制强制,并且RubyInline可能会抑制编译时产生的警告。

最终结果是该方法返回Ruby Object,其object_id等于您传入的数组的长度。对于int的大多数小值,这只是一个映射到Fixnum(即看起来像“错误的整数”)。

碰巧,2.object_id == 5这就是为什么在你期望5时得到2的原因。

修复是为了确保您返回正确的类型。您可以像这样返回VALUE

inline do |builder|
   builder.c <<-EOS
     VALUE arraylength( VALUE testarr ){
       int arrlen = RARRAY_LEN(testarr);
       return INT2NUM( arrlen );
     }
   EOS
end

或者您可以直接在int中工作,让RubyInline为您转换:

inline do |builder|
   builder.c <<-EOS
     int arraylength( VALUE testarr ){
       int arrlen = RARRAY_LEN(testarr);
       return arrlen;
     }
   EOS
end

我不使用RubyInline,但怀疑当RubyInline可以为您进行转换时,第二个版本会更受欢迎。但在幕后,它可能会改变代码看起来像第一个版本。