简体   繁体   English

gcc -O2的奇怪整数行为

[英]strange integer behavior with gcc -O2

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

When I compile the above program with gcc wtf.c , I get the expected output: 当我用gcc wtf.c编译上面的程序时,我得到了预期的输出:

42 != -2147483648
positive number: 42
97 != -2147483648
positive number: 97
-2147483648 == -2147483648
negative number: -2147483648

However, when I compile the program with gcc -O2 wtf.c , I get a different output: 但是,当我用gcc -O2 wtf.c编译程序时,我得到一个不同的输出:

42 != -2147483648
positive number: 42
97 != -2147483648
positive number: 97
-2147483648 != -2147483648
positive number: -2147483648

Note the last two lines. 注意最后两行。 What on earth is going on here? 这到底是怎么回事? Is gcc 4.6.3 optimizing a bit too eagerly? gcc 4.6.3是否过于热切地优化了?

(I also tested this with g++ 4.6.3, and I observed the same strange behavior, hence the C++ tag.) (我也用g ++ 4.6.3对它进行了测试,我发现了同样奇怪的行为,因此也就是C ++标签。)

When you do -(INT_MIN) you're invoking undefined behavior, since that result can't fit in an int. 当你执行 - (INT_MIN)时,你正在调用未定义的行为,因为该结果不适合int。

gcc -O2 notices that x can never be negative and optimizes thereafter. gcc -O2注意到x永远不会是负数并且之后会优化。 It doesn't care that you overflowed the value since that's undefined and it can treat it however it wants. 它并不关心你是否溢出了这个值,因为它是未定义的,它可以随心所欲地对待它。

I think this could help you, is from here : here 我想这可以帮到你,就是来自这里: 这里

-fstrict-overflow Allow the compiler to assume strict signed overflow rules, depending on the language being compiled. -fstrict-overflow允许编译器采用严格的签名溢出规则,具体取决于编译的语言。 For C (and C++) this means that overflow when doing arithmetic with signed numbers is undefined, which means that the compiler may assume that it will not happen. 对于C(和C ++),这意味着在对带符号数进行算术运算时溢出是未定义的,这意味着编译器可能会认为它不会发生。 This permits various optimizations. 这允许各种优化。 For example, the compiler will assume that an expression like i + 10 > i will always be true for signed i. 例如,编译器将假设类似i + 10> i的表达式对于signed i将始终为true。 This assumption is only valid if signed overflow is undefined, as the expression is false if i + 10 overflows when using twos complement arithmetic. 只有在未定义有符号溢出时,此假设才有效,因为如果使用二进制补码运算时i + 10溢出,则表达式为false。 When this option is in effect any attempt to determine whether an operation on signed numbers will overflow must be written carefully to not actually involve overflow. 当此选项生效时,必须小心写入任何确定对有符号数字的操作是否溢出的尝试,以免实际涉及溢出。 This option also allows the compiler to assume strict pointer semantics: given a pointer to an object, if adding an offset to that pointer does not produce a pointer to the same object, the addition is undefined. 此选项还允许编译器采用严格的指针语义:给定指向对象的指针,如果向该指针添加偏移量不会产生指向同一对象的指针,则添加是未定义的。 This permits the compiler to conclude that p + u > p is always true for a pointer p and unsigned integer u. 这允许编译器得出结论:对于指针p和无符号整数u,p + u> p总是为真。 This assumption is only valid because pointer wraparound is undefined, as the expression is false if p + u overflows using twos complement arithmetic. 此假设仅有效,因为指针环绕是未定义的,因为如果p + u使用二进制补码算术溢出,则表达式为false。

See also the -fwrapv option. 另请参见-fwrapv选项。 Using -fwrapv means that integer signed overflow is fully defined: it wraps. 使用-fwrapv意味着完全定义了整数签名溢出:它包装。 When -fwrapv is used, there is no difference between -fstrict-overflow and -fno-strict-overflow for integers. 使用-fwrapv时,-fstrict-overflow和-fno-strict-overflow对整数没有区别。 With -fwrapv certain types of overflow are permitted. 使用-fwrapv允许某些类型的溢出。 For example, if the compiler gets an overflow when doing arithmetic on constants, the overflowed value can still be used with -fwrapv, but not otherwise. 例如,如果编译器在对常量进行算术运算时出现溢出,则溢出的值仍然可以与-fwrapv一起使用,但不能与其他情况一起使用。

The -fstrict-overflow option is enabled at levels -O2, -O3, -Os. -fstrict-overflow选项在-O2,-O3,-Os级别启用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM