I am trying to get this Ruby inline C code http://pastie.org/2825882 to work. The code works in vanilla C, but here I get errors and warnings. What causes this error?
./backtrack_inline.rb:67: error: lvalue required as unary '&' operand
Also, why do I get the following error?
./backtrack_inline.rb:73: error: too few arguments to function 'backtrack'
Inspecting the resulting C code ( http://pastie.org/2826036) I fail to see anything wrong with the arguments. But I do also get the following warnings:
./backtrack_inline.rb:73: warning: passing argument 1 of 'backtrack' makes integer from pointer without a cast
./backtrack_inline.rb:73: warning: passing argument 2 of 'backtrack' makes integer from pointer without a cast
./backtrack_inline.rb:73: warning: passing argument 3 of 'backtrack' makes integer from pointer without a cast
Starting with this:
./backtrack_inline.rb:73: error: too few arguments to function 'backtrack'
If you look at your generated code, the backtrack
function is defined on line 29:
static VALUE backtrack(VALUE self, VALUE _ss, VALUE _s, VALUE _p, VALUE _mm, VALUE _ins, VALUE _del) { ... }
It has seven arguments, the original six, plus VALUE self
as it has been converted into a method on the Scan
class.
The call to this function, on line 67 looks like this:
end = backtrack(ss, s, p, mm, ins, del);
It has only six arguments. RubyInline doesn't convert this to a call to a method on the object, it simply copies it verbatim. This is also where the warnings about makes integer from pointer without a cast
come from: the function definition has been converted to take VALUE
s, but you're calling with the original types.
The error message says that the error is from line 73 in backtrack_inline.rb
because of the directive on line 54 of the generated code:
# line 61 "./backtrack_inline.rb"
which basically tells the compiler to "reset" its line and file values for errors, and treat the next line (55) as being line 61 in the file ./backtrack_inline.rb
. The actual line is 67, 12 ahead of 55, but the compiler reports it as being 73, 12 ahead of 61 (the value it was reset to) and from a differnt file. This technique doesn't really work in this case as it doesn't take into account the extra lines added by RubyInline. The actual line in the source is 69.
A simple fix for this is to change the definition of the backtrack
function to be just a C function rather than add it as a method on the object. Change builder.c
to builder.prefix
(on line 38 of your Ruby file). This won't work if you want to have backtrack
available as a method on the object in Ruby. If that's the case you might need create another function to be the method, which then wraps the "real" backtrack function.
Next, looking at
./backtrack_inline.rb:67: error: lvalue required as unary '&' operand
This actually refers to line 61 of the generated code, which looks like:
char* s = StringValuePtr(rb_iv_get(self, "@seq"));
StringValuePtr
is a macro which is defined as:
#define StringValue(v) rb_string_value(&(v))
This is where the &
in lvalue required as unary '&' operand
comes from. You need to add a local variable to be the lvalue:
VALUE seq = rb_iv_get(self, "@seq");
char* s = StringValuePtr(seq);
In my case (Mac OS X Snow Leopard, Ruby 1.9.3-p0, RubyInline 3.11.0) these two changes made the script run without errors, but gave the warning:
backtrack_inline.rb:47: warning: implicit conversion shortens 64-bit value into a 32-bit value
This actually refers to line 46 of the ruby file:
return (s - ss) - 1;
s
and ss
are char *
, i.e. 64 bit pointers (on this machine), and the return type of the function is int
- 32 bits. Adding an explicit cast fixed this:
return (int)((s - ss) - 1);
It now runs cleanly:
ruby-inline $ ruby backtrack_inline.rb
14
ruby-inline $
(I hope 14 is the correct answer!)
Here's a version of the script with these changes.
OK, the question was also answered at Ruby Forum:
http://www.ruby-forum.com/topic/2959614
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With