1

I have the following code:

int main()
{
    char i = 0;

    for (; i++; printf("%d", i));

    printf("%d", i);

    return 0;
}

It successfully compiles and prints 1. I am new to C and I don't understand this. I thought i++ will always be true and so it will be an infinite loop.

Can someone please explain this to me?

Ank
  • 1,864
  • 4
  • 31
  • 51

2 Answers2

3

i++ is post-increment. So at the time of checking the statement, the value of i is 0, which is false. Hence, the loop breaks.

CinCout
  • 9,486
  • 12
  • 49
  • 67
  • In case of ++i, the loop will be infinite, right? If i=1, what is the behavior of the loop? – kvk30 Oct 08 '18 at 05:10
  • 3
    @kvk30 Not really. The value of `i` will progress from `1 ... 127, -128 ... -1, 0` at which point the condition will fail again. – CinCout Oct 08 '18 at 05:16
  • @CinCout -- if bare `char` is `unsigned` then it will wrap around after `i` reaches `CHAR_MAX`, but if `char` is `signed` the arithmetic will overflow and behavior is undefined. – ad absurdum Oct 08 '18 at 05:22
  • @DavidBowling Why is the behavior different for `signed` and `unsigned`? Shouldn't wrap around happen in either case? – CinCout Oct 08 '18 at 05:24
  • 2
    The Standard provides that [`unsigned` arithmetic can never overflow](https://port70.net/~nsz/c/c11/n1570.html#6.2.5p9), and instead has wraparound. But this is not so for `signed` arithmetic, which can overflow, leading to [UB since the value can't be represented in the underlying type](https://port70.net/~nsz/c/c11/n1570.html#6.5p5). Or, [see this](https://port70.net/~nsz/c/c11/n1570.html#3.4.3p3). – ad absurdum Oct 08 '18 at 05:38
  • @kvk30 So the wrap-around behavior is valid only if the `char` is `unsigned`. So the values of `i` will range from `1...255, 0` at which point the condition will fail. If the `char` is `signed` underlying, it is `undefined behavior` and seeing the wrap-around is just one of many possible deceptive outcomes of UB. – CinCout Oct 08 '18 at 05:44
2
    for (; i++; printf("%d", i));

is legal C code, but is not idiomatic C code. Real C programmers never code like this (but can understand what happens). Read n1570 (it practically is the C standard) §6.8.5.3 for the meaning of for:

6.8.5.3 The for statement

1 The statement

      for ( clause-1 ; expression-2 ; expression-3 ) statement

behaves as follows: The expression expression-2 is the controlling expression that is evaluated before each execution of the loop body. The expression expression-3 is evaluated as a void expression after each execution of the loop body. If clause-1 is a declaration, the scope of any identifiers it declares is the remainder of the declaration and the entire loop, including the other two expressions; it is reached in the order of execution before the first evaluation of the controlling expression. If clause-1 is an expression, it is evaluated as a void expression before the first evaluation of the controlling expression.158)

2 Both clause-1 and expression-3 can be omitted. An omitted expression-2 is replaced by a nonzero constant.

Footnotes

158) Thus, clause-1 specifies initialization for the loop, possibly declaring one or more variables for use in the loop; the controlling expression, expression-2, specifies an evaluation made before each iteration, such that execution of the loop continues until the expression compares equal to 0; and expression-3 specifies an operation (such as incrementing) that is performed after each iteration.

So, in your case, the controlling expression (the "expression-2" in the C standard) is (wrongly) i++. It happens to be false on the first time the loop is taken.

If you replace i++ by ++i the condition stays true for 255 times on my Linux computer (since I have unsigned chars on 8 bits).

If your computer has signed chars, you technically have some undefined behavior, because you have a signed overflow. So be very scared and read Lattner's blog on UB!

I am new to C and I don't understand this.

Then you should read some C reference site, sometimes refer to the C11 standard n1570, read good books on C programming (perhaps even read good introduction to programming, such as SICP - which does not use C), and learn how to debug small programs. If you use some GCC compiler, be sure to enable all warnings and debug info, so compile with gcc -Wall -Wextra -g.

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • Why is it undefined behaviour for signed chars? why is it different from unsigned chars? – Ank Oct 08 '18 at 05:31
  • IIRC signed overflow is an instance of undefined behavior. – Basile Starynkevitch Oct 08 '18 at 05:32
  • okay, but why is its behaviour different from unsigned chars? why is it not wrapping around CHAR_MAX, like unsigned chars – Ank Oct 08 '18 at 05:34
  • 2
    Because the specification says that the behavior is in principle different. In practice, on your x86 computer running Linux, it is likely to be very similar for `signed` and `unsigned` char. In principle, it is not. – Basile Starynkevitch Oct 08 '18 at 05:35
  • Yeah, in my computer the behaviour is indeed same! Thanks for clearing this up! – Ank Oct 08 '18 at 05:37
  • 1
    You absolutely need to read more about undefined behavior, notably [Lattner's blog](http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html) on it – Basile Starynkevitch Oct 08 '18 at 05:38