Search code examples
clanguage-lawyerundefined-behaviorsequence-pointsorder-of-execution

Why does this code print 1 2 2 and not the expected 3 3 1?


Notice: this is a self-Q/A and a more visible targeting the erroneous information promoted by the book "Let us C". Also, please let's keep the out of the discussion, this question is about C.

I am reading the book "Let us C" by Yashwant Kanetkar.

In the book there is the following example:

#include <stdio.h>

int main(void) {
    int a = 1;
    printf("%d %d %d", a, ++a, a++);
}

The author claims that this code should output 3 3 1:

Surprisingly, it outputs 3 3 1. This is because C’s calling convention is from right to left. That is, firstly 1 is passed through the expression a++ and then a is incremented to 2. Then result of ++a is passed. That is, a is incremented to 3 and then passed. Finally, latest value of a, i.e. 3, is passed. Thus in right to left order 1, 3, 3 get passed. Once printf( ) collects them it prints them in the order in which we have asked it to get them printed (and not the order in which they were passed). Thus 3 3 1 gets printed.

However when I compile the code and run it with clang, the result is 1 2 2, not 3 3 1; why is that?


Solution

  • The author is wrong. Not only is the order of evaluation of function arguments unspecified in C, the evaluations are unsequenced with regards to each other. Adding to the injury, reading and modifying the same object without an intervening sequence point in independent expressions (here the value of a is evaluated in 3 independent expressions and modified in 2) has undefined behaviour, so the compiler has the liberty of producing any kind of code that it sees fit.

    For details, see Why are these constructs using pre and post-increment undefined behavior?