What is printf's behaviour when printing an int as float?

萝らか妹 提交于 2019-12-17 14:43:22

问题


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

回答1:


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.


回答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.)




回答3:


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).



来源:https://stackoverflow.com/questions/8203754/what-is-printfs-behaviour-when-printing-an-int-as-float

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!