1

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

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
Shanpriya
  • 125
  • 2
  • 2
  • 7
  • 3
    `printf("%f",sizeof(arr));` is undefined, second don't use `void main` use `int main` – Grijesh Chauhan Oct 12 '13 at 15:22
  • 3
    Because `%f` expects a `double`, whereas you are passing it a `size_t`. That's undefined behavior. –  Oct 12 '13 at 15:23
  • @GrijeshChauhan why do you say its undefined? Do you mean that %f only expects double value? – Shanpriya Oct 12 '13 at 15:34
  • @Shanpriya read below updated answer. – Grijesh Chauhan Oct 12 '13 at 15:45
  • 1
    @Shanpriya A good reference [C Printf and Scanf Reference](http://wpollock.com/CPlus/PrintfRef.htm) – Grijesh Chauhan Oct 12 '13 at 15:50
  • **You lied to the compiler.** You stated "I'll give you a double" with "%f" but then gave an unsigned integral type as the argument. That's *undefined behavior* and compilers are allowed to even refuse to compile such code. – Jens Oct 12 '13 at 20:43

3 Answers3

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.

Crowman
  • 25,242
  • 5
  • 48
  • 56
3

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

simonc
  • 41,632
  • 12
  • 85
  • 103
  • 4
    and correct format string is `%zu` for sizeof (in mcrosoft use `%lu`) – Grijesh Chauhan Oct 12 '13 at 15:25
  • so %zu is used to define sizeof and even %d is a wrong way to declare? – Shanpriya Oct 12 '13 at 15:32
  • 1
    @simonc I think add `"If a conversion specification is invalid, the behavior is undefined"` from [`C standard (6.5.2.2 paragraph 6)`](http://stackoverflow.com/questions/4664100/does-printfx-1-invoke-undefined-behavior) OP has doubt as he commented to me. – Grijesh Chauhan Oct 12 '13 at 15:44
3

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.

Gangadhar
  • 10,248
  • 3
  • 31
  • 50