1

I am using dev cpp on windows7 to compile my code.

int d = 0x12;
char* e = (char*)&d;
printf("%d %d\n", sizeof (int), sizeof (float));
printf("%p %p\n", &d, (float*)&d);
printf("%p %p %p %p %p\n", &d, &e[0], &e[1], &e[2], &e[3]);
printf(" %d | %x | %#1x | %#1x | %#1x |%p\n", d,  e[0], e[1], e[2], e[3], &e[0]);
getchar();

4 4 
0028FF40 0028FF40
0028FF40 0028FF40 0028FF41 0028FF42 0028FF43  
18 | 12 | 0 | 0 | 0 |0028FF40

You an see that if I use %d for printing d, it is printing the 4 bytes of e fine. But if I use %f like below, it shows zeros in the place where the first byte of e have to be printed. Anyone can help with why this happens? Why should e's contents depend on how d is formatted?

int d = 0x12;
char* e = (char*)&d;
printf("%d %d\n", sizeof (int), sizeof (float));
printf("%p %p\n", &d, (float*)&d);
printf("%p %p %p %p %p\n", &d, &e[0], &e[1], &e[2], &e[3]);
printf(" %f | %x | %#1x | %#1x | %#1x |%p\n", d,  e[0], e[1], e[2], e[3], &e[0]);
getchar();

The output is:

4 4
0028FF40 0028FF40
0028FF40 0028FF40 0028FF41 0028FF42 0028FF43
 0.000000 | 0 | 0 | 0 | 0x28ff40 |76869F1D
mskfisher
  • 3,291
  • 4
  • 35
  • 48
ada
  • 321
  • 5
  • 12
  • 3
    You should stop using Dev-Cpp. It's extremely outdated and uses an ancient version of GCC. – ThiefMaster Nov 20 '11 at 18:50
  • Why are you casting `(int*)` to `(float*)`? Programming is hard enough as it is without stuff like this. – David Heffernan Nov 20 '11 at 19:30
  • Possible duplicate of [What can happen if printf is called with a wrong format string?](http://stackoverflow.com/questions/14504148/what-can-happen-if-printf-is-called-with-a-wrong-format-string) – phuclv May 06 '17 at 09:37

3 Answers3

8

Undefined behaviour.

In practice, what you're seeing is probably due to the fact that %f makes printf pull a double from its argument list, which is 8 bytes*. But d is only 4 bytes in size, so now everything is misaligned.

Remember that printf is a variadic function, which means it's completely non-type-safe; printf has to extract raw bytes from the stack without any help from the compiler. It's entirely up to you to ensure that the arguments correspond precisely to the format string.


* Probably.
Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • I took your answer as meaning that the bytes of e are still there but it is just that it reads them from wrong place. I could verify with by making a casted printf in the next line. printf(" %f | %x | %#1x | %#1x | %#1x |%p\n", (float)d, e[0], e[1], e[2], e[3], &e[0]); This actually gave the right results. Thanks for the explanation. – ada Nov 20 '11 at 19:00
2

You're getting tripped up by automatic type promotion.

You seem to be assuming that since sizeof(int) == sizeof(float), you can pass d as a float or an int interchangeably. But the thing is, in C you can't pass a float.

In C, when you use a char or a short in an expression, it is automatically converted into an int. Similarly, when you use a float in an expression, it is automatically converted into a double.

So, when you do a printf("%f", d), the compiler pushes an int, that is to say, four bytes, onto the stack, before making the function call. Then in the function, printf() sees "%f", and pulls eight bytes off the stack. Four bytes of which are your "d", and the other four are whatever happen to be there. In your example, e[0] and e[1].

If you want to print "d" as a float, you need to explicitly cast it, or assign to a float variable. In either case, the compiler will convert it into a double before calling printf(). (Note: as odd as it may sound, "%f" is used to print doubles, not floats. You can't print floats. You can read floats, or doubles, with "%f" and "%lf", in scanf(), but in printf(), "%f" prints doubles.)

Jeff Dege
  • 11,190
  • 22
  • 96
  • 165
  • *"when you use a float in an expression, it is automatically converted into a double."* This is false. Floats do not get implicitly converted to double on all expressions, unless other operand in expression is double (*Usual arithmetric conversion*). What you are after are called *default argument promotions*, which happen **only** when A) float is passed to function without prototype, or B) float is passed to function which takes variable arguments (prototype ends with `, ...`). – user694733 Jan 26 '16 at 08:11
1

Yes, you are pulling 8 bytes off the stack - four of which are 0x00000012, the rest being compiler-dependent (perhaps the return address which was pushed onto the stack when the stack frame for printf was constructed).

Omri Gazitt
  • 3,428
  • 2
  • 21
  • 27