printf 和 gcc -O 选项更改 return 值

printf and gcc -O option change return value

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

在下面的代码中 isTmax 是我的函数 return 1 如果输入是最大的 int 值。

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;
}

然后突然又开始工作了。

我想知道为什么 return 值不同。

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

现代编译器可以(滥用)使用未定义的行为来简化、缩短和加速编译后的代码,而不会违反任何规则。我建议您阅读 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,您将强制优化器进入 de-optimizing,因此您最终得到的代码与您未优化程序时得到的代码相同。