fre*_*low 9 c c++ gcc integer compiler-optimization
#include <stdio.h>
#include <limits.h>
void sanity_check(int x)
{
if (x < 0)
{
x = -x;
}
if (x == INT_MIN)
{
printf("%d == %d\n", x, INT_MIN);
}
else
{
printf("%d != %d\n", x, INT_MIN);
}
if (x < 0)
{
printf("negative number: %d\n", x);
}
else
{
printf("positive number: %d\n", x);
}
}
int main(void)
{
sanity_check(42);
sanity_check(-97);
sanity_check(INT_MIN);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
当我用上面的程序编译时gcc wtf.c
,我得到了预期的输出:
42 != -2147483648
positive number: 42
97 != -2147483648
positive number: 97
-2147483648 == -2147483648
negative number: -2147483648
Run Code Online (Sandbox Code Playgroud)
但是,当我编译程序时gcc -O2 wtf.c
,我得到一个不同的输出:
42 != -2147483648
positive number: 42
97 != -2147483648
positive number: 97
-2147483648 != -2147483648
positive number: -2147483648
Run Code Online (Sandbox Code Playgroud)
注意最后两行.这到底是怎么回事?gcc 4.6.3是否过于热切地优化了?
(我也用g ++ 4.6.3对它进行了测试,我发现了同样奇怪的行为,因此也就是C++标签.)
Per*_*son 15
当你执行 - (INT_MIN)时,你正在调用未定义的行为,因为该结果不适合int.
gcc -O2注意到x永远不会是负数并且之后会优化.它并不关心你是否溢出了这个值,因为它是未定义的,它可以随心所欲地对待它.
ped*_*dr0 12
我想这可以帮到你,就是来自这里:这里
-fstrict-overflow允许编译器采用严格的签名溢出规则,具体取决于编译的语言.对于C(和C++),这意味着在对带符号数进行算术运算时溢出是未定义的,这意味着编译器可能会认为它不会发生.这允许各种优化.例如,编译器将假设类似i + 10> i的表达式对于signed i将始终为true.只有在未定义有符号溢出时,此假设才有效,因为如果使用二进制补码运算时i + 10溢出,则表达式为false.当此选项生效时,必须小心写入任何确定对有符号数字的操作是否溢出的尝试,以免实际涉及溢出.此选项还允许编译器采用严格的指针语义:给定指向对象的指针,如果向该指针添加偏移量不会产生指向同一对象的指针,则添加是未定义的.这允许编译器得出结论:对于指针p和无符号整数u,p + u> p总是为真.此假设仅有效,因为指针环绕是未定义的,因为如果p + u使用二进制补码算术溢出,则表达式为false.
另请参见-fwrapv选项.使用-fwrapv意味着完全定义了整数签名溢出:它包装.使用-fwrapv时,-fstrict-overflow和-fno-strict-overflow对整数没有区别.使用-fwrapv允许某些类型的溢出.例如,如果编译器在对常量进行算术运算时出现溢出,则溢出的值仍然可以与-fwrapv一起使用,但不能与其他情况一起使用.
-fstrict-overflow选项在-O2,-O3,-Os级别启用.
归档时间: |
|
查看次数: |
536 次 |
最近记录: |