0
#include <stdio.h>

int main()
{
    signed char x = 0;
    for (; x >= 0; x++);
    printf("%d\n", x);
    return 0;
}

The output of this code is -128. Can anyone explain why?

kaylum
  • 13,833
  • 2
  • 22
  • 31
  • 1
    _"...When signed integer arithmetic operation overflows (the result does not fit in the result type), the __behavior is undefined__, — the possible manifestations of such an operation include:..."_ see - https://en.cppreference.com/w/cpp/language/operator_arithmetic#Overflows – Richard Critten Aug 29 '21 at 20:29
  • 2
    @Jarod42: There is no undefined overflow here. The behavior is implementation-defined, not undefined. Per C 2018 6.5.2.4, `x++` behaves like `x += 1`. Per 6.5.16.2, `x += 1` behaves like `x = x+1` except the lvalue `x` is evaluated only once. Per 6.5.16.1, `x = x+1` converts the right side to the type of the left side. Per 6.3.1.3 3, when the right side cannot be represented in the new type (as when the right side is 128 for a left side that is eight-bit two’s complement `signed char`), either the result is implementation-defined or an implementation-defined signal is raised. – Eric Postpischil Aug 29 '21 at 20:38
  • @RichardCritten: There is no undefined behavior here, per my above comment. – Eric Postpischil Aug 29 '21 at 20:39
  • 1
    @molbdnilo: There is no undefined behavior here. See above comments and [chux’ answer](https://stackoverflow.com/a/68976703/298225). – Eric Postpischil Aug 29 '21 at 20:41
  • @EricPostpischil The Q was tagged C++ when I commented - https://eel.is/c++draft/expr.pre#4 – Richard Critten Aug 29 '21 at 20:55
  • 1
    @RichardCritten: In C++, as in C, the operands are promoted to `int`, there is no overflow in the addition, the sum is converted to `signed char`, and the result is implementation-defined. – Eric Postpischil Aug 29 '21 at 21:01
  • @EricPostpischil: one of the implementation defined might be infinite loop which is UB (at least in C++, original tag) :-). – Jarod42 Aug 29 '21 at 21:26
  • 1
    @Jarod42: The C standard requires the implementation to define the behavior of the conversion, which must either be to return a value that the implementation defines or to raise a signal that the implementation defines. The implementation may not define the behavior of the conversion to cause the loop to be an infinite loop. C++ is the same in this regard. – Eric Postpischil Aug 29 '21 at 21:30
  • @EricPostpischil: Chux's answer state that value might stay at 127, so infinite loop – Jarod42 Aug 29 '21 at 21:33
  • @Jarod42: Yes, the implementation can define the value resulting from the conversion in such a way that an infinite loop results in this particular code. It cannot, however, define the behavior of the conversion to cause an infinite loop; i.e., it cannot state that wherever such a conversion appears, the loop it is in will not or might not terminate. What it can define is limited. Regardless, there is no undefined behavior here. – Eric Postpischil Aug 29 '21 at 21:38
  • `for (;;);` is UB in C++ ([optimizing-away-a-while1-in-c0x](https://stackoverflow.com/questions/3592557/optimizing-away-a-while1-in-c0x)) (but not in C ([is-an-empty-infinite-loop-undefined-behavior-in-c](https://stackoverflow.com/questions/15595493/is-an-empty-infinite-loop-undefined-behavior-in-c))). – Jarod42 Aug 29 '21 at 21:43
  • @EricPostpischil I stand corrected (learning is fun) but I think it might be well defined in the latest draft https://eel.is/c++draft/expr.ass#3 then https://eel.is/c++draft/conv#integral-3 – Richard Critten Aug 29 '21 at 21:48
  • @EricPostpischil: operands are promoted to `int` only if `sizeof(char) < sizeof(int)` ;) (we can have both equal to 1 (with "big" char)). – Jarod42 Aug 29 '21 at 21:57

2 Answers2

3

Implementation-defined behavior

signed char x = 0; for (; x >= 0; x++); iterates x from 0 up to 127 (SCHAR_MAX), all OK so far.

On the next iteration, x++ acting like x = x + 1;, attempts to assign 128 to the signed char x. As that is out of signed char range:

Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.
(C spec relating to conversions to a signed type)

A common implementation-defined result is to wrap around to -128 or SCHAR_MIN. Other results could have happened, like assigning a max value of 127 resulting in an infinitive loop.

There is no signed integer overflow, just an out of range assignment.


Code is not highly portable and should be avoided.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
-1

It is implementation-defined behaviour.

on x86 platform all known to me compilers, when x is 127 and you add 1 it performs unsigned addition and the result is 0b10000000 which in two's complement signed integer format is -128

As x is -128 the loop terminates and -128 is printed out

0___________
  • 60,014
  • 4
  • 34
  • 74
  • Half right. The behavior is implementation-defined. It is defined by the C implementation, largely the compiler, not by the “platform.” C compilers may deliver any behavior permitted by the C standard; they are not obligated to use the instruction set mindlessly. – Eric Postpischil Aug 29 '21 at 20:43