Undefined Behaviour
Eric Bailey
Written on 7 May, 2018
Updated on 26 August, 2024
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) { int x, y; 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
.
gcc (GCC) 13.2.0 incdec.c: In function ‘main’: incdec.c:8:9: warning: operation on ‘x’ may be undefined [-Wsequence-point] 8 | y = ++x + --x; | ^~~ x = 10, y = 20
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
.
clang version 17.0.6 incdec.c:8:9: warning: multiple unsequenced modifications to 'x' [-Wunsequenced] 8 | y = ++x + --x; | ^ ~~ 1 warning generated. x = 10, y = 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.