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,因此您最终得到的代码与您未优化程序时得到的代码相同。
我正在尝试了解 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,因此您最终得到的代码与您未优化程序时得到的代码相同。