6

I'm currently learning C program But I came across some weird behavior I expected one result but two results is printed like this

$ ./a.out
yes1 0x80000000
yes3 0x80000000

How could possible that?
I can't understand the result.

OS : x86_64 Ubuntu Linux
C compiler : gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1

gcc -O2 weird.c

#include <stdio.h>

int main() {

    int i = 0x7fffffff;
    int ii = 0x0000000f;

    if ((i + 1) < ii)
        printf ("yes1 %#x\n", i + 1);

    if ((i + 1) == ii)
        printf ("yes2 %#x\n", i + 1);

    if ((i + 1) > ii)
        printf ("yes3 %#x\n", i + 1);

    return 0;
}
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
mug896
  • 1,777
  • 1
  • 19
  • 17

3 Answers3

7

In your case (i+1) is overflowing over the range of the integer variable.

The truth is that overflow on a signed int variable is an undefined behaviour in ANSI standard, so strictly speaking it may lead to any result. Your compiler may be conform to the standard but anyone with good computer understanding would expect that the variable will overflow to negative values simply because computer registers do not distinct signed/unsigned ranges.

Here is what ANSI standard says on Undefined behavior (among other cases):

The behavior in the following circumstances is undefined:

An arithmetic operation is invalid (such as division or modulus by 0) or produces a result that cannot be represented in the space provided (such as overflow or underflow) ($3.3).

On the other side, this is not valid for unsigned types:

A computation involving unsigned operands can never overflow, because a result that cannot be represented by the resulting unsigned integer type is reduced modulo the number that is one greater than the largest value that can be represented by the resulting unsigned integer type.

Also here is the related part from referred section ($3.3 Expressions):

If an exception occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not representable), the behavior is undefined.

Marian
  • 7,402
  • 2
  • 22
  • 34
  • One could set `-fwrapv`, which makes overflow fully defined as wrapping around. – Hasturkun Mar 31 '14 at 12:43
  • Presumably `-fwrapv` would disable the problematic optimization mentioned in my answer. – keshlam Mar 31 '14 at 12:50
  • It looks like you are quoting the annex which is not normative, although I can not find that wording in either draft C99 nor draft C11 are you quoting C89? ANSI is vague, today I would take that to mean C11. – Shafik Yaghmour Mar 31 '14 at 12:55
  • @ShafikYaghmour I am not 100% sure but I think it is one of lasts drafts for C89. – Marian Mar 31 '14 at 12:58
  • You should quote the normative text as well, I am pretty sure that is C89 since section `3` is *terms and definitions* in both C99 and C11. This [thread](http://stackoverflow.com/questions/81656/where-do-i-find-the-current-c-or-c-standard-documents) has all the public drafts available so you can pull both C99 and C11 drafts from the links provided there. – Shafik Yaghmour Mar 31 '14 at 13:02
3

In all the cases in your code i+1 is producing signed integer overflow which is undefined behavior, which means the program can behave unpredictably. We can see it is undefined from the draft C99 standard section 6.5 Expressions paragraph 5 which says(emphasis mine):

If an exceptional condition occurs during the evaluation of an expression (that is, if the result is not mathematically defined or not in the range of representable values for its type), the behavior is undefined.

It is the same section in the draft C11 standard as well.

One possible way to have caught this would be use clangs -fsanitize=undefined option which is part clangs santizer suite we get the following runtime errors:

runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
Community
  • 1
  • 1
Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
2

I think you're running into an optimizer case where the compiler is saying that for integers, x+1>y can be computed more efficiently as x>=y... and unfortunately while that's generally true, and is always true for unsigned values, this one specific case where x+1 wraps around to be negative breaks the assumption.

However, since signed int overflow gets us into the realm of undefined behavior (see @Marian's answer), this is not incorrect. Just surprising.

(Thought about deleting my answer, but since it illustrates how both tests could be true I think it's worth keeping.)

keshlam
  • 7,931
  • 2
  • 19
  • 33
  • This isn't a compiler bug. Signed integer overflow is undefined behavior. – Hasturkun Mar 31 '14 at 12:46
  • Thanks; clarified appropriately. – keshlam Mar 31 '14 at 12:52
  • The specific optimization in play here is `-fstrict-overflow`. Under `-O2`, gcc enables the `-fstrict-overflow` optimization, which allows it to assume that signed overflow is undefined. using `-fwrapv` makes the compiler assume that overflow causes wraparound instead. As an amusing aside, in the C99 specification, sec 3.4.3, the example given for the definition of undefined behavior says "An example of undefined behavior is the behavior on integer overflow" – Hasturkun Mar 31 '14 at 12:52