【问题标题】:printf and gcc -O option change return valueprintf 和 gcc -O 选项改变返回值
【发布时间】:2019-10-19 00:01:41
【问题描述】:

我正在尝试了解 gcc -O 选项和 printf 如何更改返回值。

isTmax 下面的代码是我的函数,如果输入是最大的 int 值,则返回 1。

int isTmax(int x);
int main(void)
{
    printf("%d\n", isTmax(0x7fffffff));
}

int isTmax(int x)
{
    int temp = x + x + 2;
    int result = !temp & (!!(~x));
    return result;
}

当我在没有 gcc 选项的情况下编译它时它工作得很好。

但是使用 -O 选项,我得到所有整数值的 0。

所以我添加了 printf 来检查值,然后用 -O 选项编译它。

int isTmax(int x)
{
    int temp = x + x + 2;
    int result = !temp & (!!(~x));
    printf("x : %x, temp : %x, !temp : %x\n", x, temp , !temp); 
    return result;
}

然后它突然又开始工作了。

我想知道为什么返回值会变化。

【问题讨论】:

  • 了解UB
  • @pmg 添加,用于签名溢出。在这里使用0x7fffffff 意味着已经处于边缘
  • 具体来说,文档指出signed integer overflows可能会被完全优化掉...
  • 您可以使用return x == INT_MAX; 简化此操作,它位于limits.h 中。
  • 谢谢各位!我以为 printf 改变了一些东西

标签: c gcc return-value


【解决方案1】:

正如在 cmets 中指出的那样,这是因为未定义的行为。

现代编译器可以(ab)使用未定义的行为来简化、缩短和加速编译代码,而不会违反任何规则。我建议你阅读excellent article 了解 UB 的危险。

很难知道究竟发生了什么,因为优化器变得非常复杂,但这里有一个关于编译器可能对你的函数做些什么的看法。

(1) int isTmax(int x)
(2) {
(3)     int temp = x + x + 2;
(4)     int result = !temp & (!!(~x));
(5)     return result;
(6) }

在第 3 行,您将两个有符号整数相加。如果您的程序仅使用0x7fffffff 调用此函数一次,则编译器已经知道代码只会产生整数溢出。该代码有一个转折;由于您将 2 添加到溢出操作中,因此编译器可以假定该值将是正数并且大于 2,以便接下来发生什么。

在第 4 行,!temp 转换为布尔常量 false,因为 temp 被假定为正值。接下来,and;由于左边的值为 false(或 0),result 总是以 0 结束。如果结果总是为零,优化器不妨删除所有变量和操作。

所以本质上,优化后,你的函数看起来像:

int isTmax(int x)
{
    return 0;
}

通过在函数中添加printf,您将强制优化器进行反优化,因此您最终会得到与未优化程序时相同的代码。

【讨论】:

    猜你喜欢
    • 2021-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多