Why am I not getting the same value as I get with %d
and not with %f
?
void main()
{
int arr;
printf("%f",sizeof(arr));
}
Output: 2.168831
void main()
{
int arr;
printf("%d",sizeof(arr));
}
output: 4
Why am I not getting the same value as I get with %d
and not with %f
?
void main()
{
int arr;
printf("%f",sizeof(arr));
}
Output: 2.168831
void main()
{
int arr;
printf("%d",sizeof(arr));
}
output: 4
To give a bit more of an explanation, it's because printf()
is a variadic function, and the types of the arguments are not known until the function runs and determines what they are from the format string. This means that the normal implicit conversions will not occur.
For instance, if you do something like:
void myfunc(double d) {
/* Do something with d */
}
int main(void) {
int n = 5;
myfunc(n);
return 0;
}
then the compiler knows that myfunc()
takes an argument of type double
, and therefore can and will implicitly convert n
from int
to double
before passing the parameter.
When you do:
int main(void) {
double f = 5.5;
printf("%d\n", f); /* WARNING: buggy code */
return 0;
}
the compiler has no idea what type printf()
is expecting until it runs and makes sense of the %d
in the format string. So, all it can do is pass the double
argument as a double
, and when printf()
runs and sees the %d
, it'll interpret it as an int
and things will start going horribly wrong when it misinterprets the bit pattern (and, in this case, probably the size of the argument, as well, throwing it off for any other arguments which come after it).
This is, among other things, the reason why these functions are one of the rare occasions where casts to void *
are actually necessary in C, since pointers to different types of objects are allowed to be different sizes, and since %p
expects a void *
, you have to pass it a void *
, and not a pointer to any other object type.
Note, though, that modern compilers can be smart, and they know how standard C functions work, so they can just be informed about the standard behavior of functions like printf()
such that they can give you warnings about mismatched argument types like this, although they won't actually fix them for you.
sizeof
returns size_t
but printf("%f",...
tells printf
that the next argument has type double
. size_t
has a different layout in memory from double
so printf
incorrectly interprets this argument.
As Grijesh points out, the correct format specifier to use would be %zu
but if you really want to use %f
printf("%f",(double)sizeof(arr));
would work
sizeof
operator returns `size_t
You should use %zu
format specifier with printf()
Note that size_t
is unsigned
, signed
sizes can be represented by ssize_t
.
Both of these types are defined in the stddef.h
header
§7.21.6.1 p9 of the C11 standard says
If a conversion specification is invalid, the behavior is undefined. If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.