Strange behavior in C when comparing integers

This issue occurs in my mac environment where the gcc version is shown below:

Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 7.0.2 (clang-700.1.81)
Target: x86_64-apple-darwin14.5.0
Thread model: posix

      

The code segment refers to one of the functions.

int someFunction(int x, int n) {
    int TMin_n = -(1 << (n-1));
    int TMax_n = (1 << (n-1)) - 1;
    int a = -2147483648;
    printf("%s\n", x == a ? "true" : "false");      // true
    printf("%s\n", x <= TMax_n ? "true" : "false"); // false
    printf("%s\n", a <= TMax_n ? "true" : "false"); // true
    printf("%d %d %d\n", TMin_n, x, TMax_n);        // -2147483648 -2147483648 2147483647
    return 0;
}

      

a equals x, but why do they have different behavior when compared to TMax_n?

UPDATE

all data types in this code segment int

.

UPDATE2

Thanks everyone. I just tried the same code on an ubuntu machine and it works fine. It only got stuck on my MAC.Seems that it is a compiler related issue.

+3


source to share


2 answers


It seems that due to undefined behavior in the expression (1 << (n-1)) - 1

, especially in (1 << (n-1))

since it is 1

treated as int

(possibly 32 bits) and the expression (1 << (n-1))

then gives a value that exceeds the maximum value represented by the character int

. So this (intermediate) result results in an integer arithmetic overflow value, which is UB (see cppreference ):

When an integer arithmetic overflow operation is declared (the result does not match the type of the result), the behavior is undefined: it can be wrapped around according to presentation rules (usually 2's complement), it can depend on some platforms, or because of compiler capabilities (e.g. -ftrapv in GCC and Clang), or the compiler can be fully optimized.

Therefore, it may work on some compilers, it may not work on others. However, if you added to unsigned int

before the bit-crash, the overflow will disappear and you will fall back into certain (and expected) behavior:



(int) (((unsigned)1 << (n-1)) - 1)

      

BTW: if you set -ftrapv

to "other compiler options" for the C compiler, expressions int TMin_n = -(1 << (n-1))

and will int TMax_n = (1 << (n-1)) - 1

throw a runtime exception (for example EXC_BAD_INSTRUCTION

).

+5


source


I tried your snippet using the clang online compiler and got the results from the question. I am assuming that the code (including the function call) is fully inlined and then the compiler will optimize any comparisons it finds constant.

This line seems to be:

int TMax_n = (1 << (n-1)) - 1;

      



If I explicitly cast (1 << (n-1))

in unsigned

, the problem goes away:

int TMax_n = (int) ((unsigned)(1 << (n-1)) - 1);

      

+3


source







All Articles