It's undefined behaviour, so there's no "why" that can be given without analysing the implementation in detail. But most likely, the layout of the variables the compiler chose caused some of them to be clobbered when reading into the others.
With my compiler, after adding a line printing out the addresses of a, b, d, e
, I got the output
0
70
0x7fffa94d30ca
0x7fffa94d30c8
0x7fffa94d30c6
0x7fffa94d30c4
so what happened is probably¹
- the scan into
a
stored 10 in the low order byte at 0x7fffa94d30ca
, 0 in the next three bytes (little-endian machine), overwriting two bytes of the stack that weren't allocated for any of the variables, unfortunately without fatal consequences,
- the scan into
b
stored 20 in the byte at 0x7fffa94d30c8
, 0 into the next three bytes, overwriting the two bytes allocated for a
, hence setting a
to 0,
- the scan into
e
(cleverly done out of alphabetical and declaration order) stored 30 in the byte at 0x7fffa94d30c4
and 0 into the next three bytes, the last two of which were where d
was allocated, but d
is scanned into afterwards, so
- the scan into
d
stored 40 in the byte at 0x7fffa94d30c6
and 0 in the next three bytes, overwriting b
with 0,
- the addition
c = a + b
results in 0, since both variables were overwritten when scanning into other variables and the addition f = d + e
results in 70 since neither of d
and e
was overwritten after the scan.
Forcing c
to be allocated on the stack, and not being placed in a register by printing out its address led here to the scan into d
overwriting c
instead of b
and correspondingly the addition c = a + b
resulted in 20.
¹ Since it's undefined behaviour to scan into short int
variables using the %d
format specifier, anything could happen, but if the compiler doesn't go out of its way to exploit UB, the simple explanation will be the correct one.