Undefined Behaviour

Eric Bailey

Written on 7 May, 2018
Updated on 18 December, 2023
Tags: c, compilers, school, facepalm

A friend at work today was telling me about his wife's C​++ class, wherein the students were asked to predict the behaviour of the following snippet.

x = 10;
y = ++x + --x;

Example

For simplicity, let's assume the type of both x and y is int.

int x, y;

We can inspect the final state of x and y with a simple printf call.

printf("x = %d, y = %d\n", x, y);

Now, let's see how different compilers handle our program.

#include <stdio.h>


int main(int argc, char **argv)
{
    x = 10;
    y = ++x + --x;

    printf("x = %d, y = %d\n", x, y);
}

At first glance, I would expect the right-hand side of the initialization of y to evaluate to 11 + 10, i.e. 21.

Curiouser and curiouser!

Unsurprisingly, GCC computes the final value of x to be 10, the same as its initial value, after being incremented and decremented. It's markedly less intuitive to me that the final value of y is 20.

Clang, on the other hand, agrees with me, i.e. computes the final value of y to be 21.

The more you know

Both compilers warn about unsequenced modifications and the resultant undefined behaviour. Digging around a bit leads to some fascinating discussions. The GCC team maintains a list of further reading, including a few formal models and analyses of sequence points in C. Further exploration is left as an exercise for the reader.

tl;dr

It is not specified when between sequence points modifications to the values of objects take effect.

⋯

The standard is worded confusingly, therefore there is some debate over the precise meaning of the sequence point rules in subtle cases.