stackoverflower
stackoverflower

Reputation: 4063

How printf handles conversion

I'm reading chapter 7 of C programming: a modern approach, and a bit unclear how printf handles type conversion.

Consider the following code:

int main() {
    int i = 47000; // This will overflow when squared

    int i2 = square(i);

    long l = square(i);

    printf("i2 = %ld, l = %ld, i * i = %ld, square(i) = %ld",
       i2, l, i * i, square(i));

    return 0;
}

int square(int i) {
    int j = i * i;
    return j;
}

I expected the output to be (due to overflowing):

i2 = -2085967296, l = -2085967296, i * i = -2085967296, square(i) = -2085967296

But instead I got:

i2 = 2209000000, l = -2085967296, i * i = 2209000000, square(i) = 2209000000

Could you explain:

a) why some results didn't overflow?

b) why l overflowed?

Upvotes: 0

Views: 87

Answers (2)

JSF
JSF

Reputation: 5321

You get undefined behavior using %ld to print ints.

What you are actually seeing is an artifact of the X86-64 parameter passing.

When you explicitly convert the int value returned by square from 32 bit to 64 bit long, you sign extend, preserving the overflow. So that one shows the expected overflow.

The first few ints passed to a function in x86-64 are zero extended to 64-bits (later ones may be garbage extended). That should be an invisible effect, because only the low 32-bit should be used. But then you used %ld causing all 64 bits to be used. The particular value had overflowed in a way that causes zero extension to 64-bit to accidentally get back to the non overflowed value.

So the undefined behavior of passing an int that the receiving function aliases as long accidentally undid the overflow.

Upvotes: 3

Pete Becker
Pete Becker

Reputation: 76438

printf doesn't do type conversions. It takes its arguments (other than the format string) through an ellipsis, so it has to trust the format string to tell it what the types of the input values are.

"%ld" tells printf that the corresponding value has type long int. The values of i2, i * i, and square(i) all have type int. So the format specifier is wrong, and the displayed values are nonsense. Use "%d" for int.

Upvotes: 0

Related Questions