编译 Ruby 内联 C 代码 - 解决错误

发布于 2024-12-14 14:44:49 字数 863 浏览 1 评论 0原文

我正在尝试让这个 Ruby 内联 C 代码 http://pastie.org/2825882 工作。该代码可以在普通 C 中运行,但在这里我收到错误和警告。导致此错误的原因是什么?

./backtrack_inline.rb:67: error: lvalue required as unary '&' operand

另外,为什么我会收到以下错误?

./backtrack_inline.rb:73: error: too few arguments to function 'backtrack'

检查生成的 C 代码 (http://pastie.org/2826036) 我没有发现参数有任何问题。但我也收到以下警告:

./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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

各自安好 2024-12-21 14:44:49

从这里开始:

./backtrack_inline.rb:73: error: too few arguments to function 'backtrack'

如果你查看生成的代码,backtrack 函数是在第 29 行定义的:

static VALUE backtrack(VALUE self, VALUE _ss, VALUE _s, VALUE _p, VALUE _mm, VALUE _ins, VALUE _del) { ... }

它有七个参数,原来的六个,加上 VALUE self 因为它有已转换为 Scan 类上的方法。

第 67 行对此函数的调用如下所示:

end = backtrack(ss, s, p, mm, ins, del);

它只有六个参数。 RubyInline 不会将其转换为对对象方法的调用,它只是逐字复制它。这也是有关makes integer frompointer without a cast的警告的来源:函数定义已转换为采用VALUE,但您正在使用原始函数调用类型。

错误消息表明错误来自 backtrack_inline.rb 中的第 73 行,因为生成代码的第 54 行上的指令:

# line 61 "./backtrack_inline.rb"

它基本上告诉编译器“重置”其行和文件值以防止错误,并将下一行 (55) 视为文件 ./backtrack_inline.rb 中的第 61 行。实际行是 67, 12 领先于 55,但编译器将其报告为 73, 12 领先于 61(重置为的值)并且来自不同的文件。这种技术在这种情况下并不起作用,因为它没有考虑 RubyInline 添加的额外行。源代码中的实际行是 69。

解决此问题的一个简单方法是将 backtrack 函数的定义更改为 C 函数,而不是将其添加为对象上的方法。将 builder.c 更改为 builder.prefix(位于 Ruby 文件的第 38 行)。如果您希望在 Ruby 中将 backtrack 作为对象的方法使用,那么这将不起作用。如果是这种情况,您可能需要创建另一个函数作为方法,然后包装“真正的”回溯函数。

接下来,查看

./backtrack_inline.rb:67: error: lvalue required as unary '&' operand

This 实际上指的是生成代码的第 61 行,它看起来像:

char* s = StringValuePtr(rb_iv_get(self, "@seq"));

StringValuePtr 是一个 宏定义为

#define StringValue(v) rb_string_value(&(v))

这是左值中的&需要作为一元的地方'&'操作数来自。您需要添加一个局部变量作为左值:

VALUE seq = rb_iv_get(self, "@seq");
char* s = StringValuePtr(seq);

在我的例子中(Mac OS X Snow Leopard、Ruby 1.9.3-p0、RubyInline 3.11.0)这两个更改使脚本运行没有错误,但给出了警告

backtrack_inline.rb:47: warning: implicit conversion shortens 64-bit value into a 32-bit value

:实际上指的是ruby文件的第46行:

return (s - ss) - 1;

ssschar *,即64位指针(在此machine),函数的返回类型为int - 32位。添加显式转换修复了这个问题:

return (int)((s - ss) - 1);

它现在可以干净地运行:(

ruby-inline $ ruby backtrack_inline.rb 
14
ruby-inline $ 

我希望 14 是正确的答案!)

这是一个 版本包含这些更改的脚本

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 VALUEs, 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.

潇烟暮雨 2024-12-21 14:44:49

好的,这个问题也在 Ruby 论坛上得到了回答:

http://www.ruby-forum.com/主题/2959614

OK, the question was also answered at Ruby Forum:

http://www.ruby-forum.com/topic/2959614

浊酒尽余欢 2024-12-21 14:44:49

好吧……再想一下这个问题。

你正在调用一个变量结束。虽然这不是 C 中的保留字 - 并且 ruby​​ 不应该查看它......也许 ruby​​ 感到困惑?

我建议您尝试重命名它以防万一。即使只是排除它也值得尝试。

Ok... thought a bit more about this.

you are calling a variable end. While this isn't a reserved word in C - and ruby shouldn't be looking at it... perhaps ruby is getting confused?

I'd suggest you have a go at renaming it just in case. Worthwhile trying even just to rule it out.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文