From: Tim Hunter Date: 2009-01-01T07:48:23+09:00 Subject: Re: Ruby arguments into C function are warped Daniel Waite wrote: > I want to code a few methods in C for speed reasons. The Pick Axe book > (2nd edition) is a wonderful guide to writing Ruby code in C, but that's > not what I want. The benchmarks I ran for the Ruby-in-Ruby and Ruby-in-C > programs showed similar results. So allow me to clarify: > > I do not want a Ruby array in C. I want a C array in C. > > Which I have done... > > int array[1000000]; > > static VALUE t_add(VALUE self, VALUE obj, VALUE i) > { > array[i] = obj; > return 1; > } > > static VALUE t_include(VALUE self, VALUE obj) > { > int size = sizeof(array) / sizeof(int); > int index; > > for(index = 0; index < size; index++) { > if(FIX2INT(obj) == FIX2INT(array[index])) { > return Qtrue; > } > } > > return Qfalse; > } > > static VALUE t_at(VALUE self, VALUE obj) > { > return array[obj]; > } > > The value of "obj" comes from within Ruby (IRB, actually). But unless I > coerce it using FIX2INT, it's always a weird value. Say I put in 1, > it'll tell me it received 31478 or something similar. > > Another thing... I thought that if I passed in an 'a' or any other > non-integer value into the add method, I'd get an error. I don't. In > fact... > > require 'my_test' > mt = MyTest.new > mt.add('a', 0) > mt.at(0) # 'a' > > But... > > mt.include?('a') # false > > So... what's happening to my arguments as they pass through Ruby and > into C? Notice that you've declared the arguments to t_add as VALUEs, not ints. This is because Ruby passes VALUE arguments to your function. A VALUE is a reference to a Ruby object. If you want to store the arguments in an int array, convert the objects to ints via FIX2INT or some other conversion function: static VALUE t_add(VALUE self, VALUE obj, VALUE i) { array[FIX2INT(i)] = FIX2INT(obj); return self; } A VALUE can reference any Ruby object, but the FIX2INT macro expects its argument to be a Ruby Fixnum. If it's not, it will raise an exception. You'll get an exception if you call mt.add("a", 0). Also, the return value from t_add should be a VALUE, not an int. It's your choice which VALUE to return. Here I chose self. -- RMagick: http://rmagick.rubyforge.org/