5

我在测试一个示例代码时遇到了一些问题,因为我的 abs 函数没有返回正确的结果。abs(-2) 正在输出 -2 (顺便说一下,这应该是绝对值函数,如果不清楚的话)

在变得有点绝望之后,我最终得到了以下代码

#include <stdio.h>

unsigned int abs(int x) {
    return 1;
}

int main() {
    printf("%d\n", abs(-2));
    return 0;
}

这没有任何用处,但它可以显示我的问题。这是输出 -2,而预期输出 1。

如果我将函数名称更改为其他名称(例如 abs2),则结果现在是正确的。此外,如果我将其更改为接收两个参数而不是一个,它也可以解决问题。

我的明显猜测:与标准 abs 函数冲突。但这仍然不能解释为什么输出是 -2(如果使用标准 abs 函数,它应该是 2)。我尝试检查两个版本的汇编输出(使用名为 abs 和 abs2 的函数)

这是两个程序集的差异输出:

23,25c23,25
< .globl abs
<   .type   abs, @function
< abs:
---
> .globl abs2
>   .type   abs2, @function
> abs2:
54c54
<   .size   abs, .-abs
---
>   .size   abs2, .-abs2
71c71,74
<   movl    -4(%rbp), %edx
---
>   movl    -4(%rbp), %eax
>   movl    %eax, %edi
>   call    abs2
>   movl    %eax, %edx

据我了解,第一个版本(函数名为 abs)只是丢弃函数调用,因此使用参数 x 而不是 abs(x)

总结一下:为什么会发生这种情况,特别是因为我找不到一种方法来获得任何关于此的警告或错误。

在 Debian Squeeze、ggc 4.4.5 和 gcc 4.1.2 上测试

4

3 回答 3

7

由于以下因素的相互作用,GCC 正在捉弄你:

  • abs是一个内置函数;
  • 您声明在标准(和内置)abs返回时返回。unsigned intabssigned int

尝试编译gcc -fno-builtin;在我的盒子上,这给出了预期的结果1。在没有该选项但abs声明为返回的情况下进行编译signed int会导致程序打印2

(这个问题的真正解决方案是不要为你自己的函数使用库标识符。还要注意你不应该打印一个unsigned intwith %d。)

于 2012-04-10T11:34:58.057 回答
2

gcc优化调用以abs()使用其内置的abs(). 因此,如果您使用该-fno-builtin选项(或将您的定义abs()为返回int),您会注意到您得到了正确的结果。据此(引用):

GCC 包括标准 C 库中许多函数的内置版本。即使您指定了 -fno-builtin 选项,带有 _ builtin前缀的版本将始终被视为与 C 库函数具有相同的含义。(请参阅 C 方言选项)其中许多功能仅在某些情况下进行了优化;如果它们在特定情况下未优化,则会发出对库函数的调用

如果你首先stdlib.h声明abs()了 include ,你会在编译时得到一个错误。

于 2012-04-10T11:36:59.247 回答
1

听起来很像这个错误,它是从 2007 年开始的,并指出已修复。

您当然应该尝试在没有 GCC 的内在函数的情况下进行编译,即在编译时通过-fno-builtin(或仅-fno-builtin-abs用于狙击abs())。

于 2012-04-10T11:38:15.113 回答