2014-02-05 68 views
2

爲什麼在我測試時此代碼返回錯誤的元素數?它似乎是正確值的一半Rubyinline爲RARRAY_LEN返回錯誤結果

我使用了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 
+0

爲什麼'C'標籤? –

+0

因爲它是內聯C. – sawa

+0

因爲從ruby.no調用c很好嗎? – user3275038

回答

1

與代碼的問題是,你需要聲明的C函數返回一個VALUE(長用於標識Ruby對象的指針類型),但返回int。編譯器可以在這裏強制執行強制轉換,而RubyInline可能會在編譯時抑制一個警告。

最終的結果是該方法返回的紅寶石Objectobject_id等於你在傳入數組的長度。對於int大多數小值,這僅僅是一個映射到Fixnum(即什麼樣子的「錯誤的整數「)。

碰巧,2.object_id == 5這就是爲什麼你會得到2,當你想到5.

的解決方法是,確保你返回正確的類型。你既可以返回一個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可以爲你做轉換時首選。但是在引擎蓋下,它可能會改變代碼,使其看起來像第一個版本。