0

When I provide the following program with 4 integers as input (say a = 10, b = 20, d = 30, e = 40), it calculates c = a + b = 0 and f = d + e = 70. I know this unusual behavior is because I am using the wrong format specifier for short int, but what exactly is happening here? Why is the sum of the last two inputs correct and the sum of the first two numbers always = 0?

#include<stdio.h>

void main()
{
    short int a, b, c, d, e, f;
    scanf("%d%d%d%d", &a, &b, &e, &d);
    c = a + b;
    f = d + e;
    printf("%d\n%d\n", c, f);
}
Bonz0
  • 373
  • 2
  • 5
  • 17
  • 2
    On many platforms, a `short` will have a size of 2 bytes and a `%d` format spec tells `scanf()` that the destination has 4 bytes. So consider what happens when `scanf()` write 4 bytes to a variable location that only has 2. – Michael Burr Jul 03 '12 at 19:05
  • 1
    possible duplicate of [Why is %hd necessary in scanf?](http://stackoverflow.com/questions/3257684/why-is-hd-necessary-in-scanf) – Bo Persson Jul 03 '12 at 19:06

3 Answers3

3

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¹

  1. 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,
  2. 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,
  3. 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
  4. the scan into d stored 40 in the byte at 0x7fffa94d30c6 and 0 in the next three bytes, overwriting b with 0,
  5. 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.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
3

"%d" is the format code used to read an int. If short is smaller than int, "%hd" is the proper format code to read a short int.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
1

What is happening is that “%d” instructs scanf to read and parse a number from the input, convert it to an int, and to store that int at the corresponding address. Commonly, an int is 32 bits (four bytes), and a short int is 16 bits (two bytes), although this can vary.

Although scanf is writing four bytes for each “%d”, you have passed it only two bytes for each of &a, &b, &e, and &d. So two of the bytes go to the correct address, and the other two go to whatever happens to be next to &a, &b, &e, and &d. Some of them are next to each other and get overwritten by the stray bytes.

Obviously, this is very broken code and should never be used. You cannot count on which variables will be next to which others in memory.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312