struct DummyStruct{
unsigned long long std;
int type;
};
DummyStruct d;
d.std = 100;
d.type = 10;
/// buggy printf, unsigned long long to int conversion is buggy.
printf("%d,%d\n",d.std, d.type); // OUTPUT: 0,100
printf("%d,%d\n", d.type, d.std); // OUTPUT: 10,100
printf("%lld,%d\n",开发者_运维百科d.std, d.type); // OUTPUT: 100,10
Please tell me why unsigned long long to int conversion is not properly handled in printf. I am using glibc.
Is this bug in printf ?
why printf does not do internal type conversion ?
The %d
argument tells printf
to interpret the corresponding argument as an int
. Try using %llu
for long long
. And memorize this reference card.
(So no, it's not a bug)
Its your usage that is the problem. Unless the types specified in the format string are exactly the same as the types in the parameters then things will not work correctly.
This is because the compiler pushes the parameters as-is onto the stack.
There is not type checking or conversion.
At run-time the code is pulling the values of the stack and advancing to the next object based on the value in the format string. If the format string is wrong then the amount advanced is incorrect and you will get funny results.
Rule one: The chances of you finding a bug in the library or the compiler are very, very slim. Always assume the compiler / library is right.
Parameters are passed to printf()
through the mechanisms in <stdarg.h>
(variable argument lists), which involves some magic on the stack.
Without going into too much detail, what printf()
does is assuming that the next parameter it has to pull from the stack is of the type specified in your format string - in the case of %d
, a signed int.
This works if the actual value you've put in there is smaller or equal in width to int
, because internally any smaller value passed on the stack is extended to the width of int
through a mechanism called "integer promotion".
This fails, however, if the type you have passed to printf()
is larger than int
: printf()
is told (by your %d
) to expect an int
, and pulls the appropriate number of bytes (let's assume 4 bytes for a 32 bit int
) from the stack.
In case of your long long
, which we'll assume is 8 bytes for a 64 bit value, this results in printf()
getting only half of your long long
. The rest is still on the stack, and will give pretty strange results if you add another %d
to your format string.
;-)
With printf (which is one of the very old functions from original C) the compiler does not cast the paramters after the format list to the desired type, i.e. you need to make sure yourself that the types in the parameter list match the one in the format.
With most other functions, the compiler squeezes the given parameter into the declared types, but printf, scanf and friends require you to tell the compiler exactly which types are following.
精彩评论