why float pointer should be printed using %f but why can't by using %d.
The conversion specification (%d or %f) tells printf two things:
- Where to find the argument that was passed.
- How to interpret the bits of that argument.
On the first point, modern processors commonly have different registers for integer data and floating-point data. Due to this and related reasons, the rules for how arguments are passed to subroutines (part of the Application Binary Interface for a computing environment) typically say that the first few integer arguments are passed in certain integer registers and the first few floating-point arguments are passed in floating-point registers. (After the first few arguments, additional arguments are typically passed on the hardware stack.)
So, when you tell printf to convert a number with %d but pass it a floating-point argument, printf may take the value from some integer register, but the floating-point argument is not there. It is in some floating-point register. And then printf prints the wrong value.
On the second point, the values of integers and floating-point numbers are encoded in bits differently. %d tells printf to interpret the bits as a binary number (along with some scheme for representing negative numbers, most frequently two’s complement). %f tells printf to interpret the bits as a number encoding with a floating-point format. Also, due to C history, float arguments to printf are passed as double. The most common floating-point format for double uses one bit for the sign, 11 bits for an exponent of two, and 52 bits for a significand portion. (In ordinary scientific notation, for the numeral −3.74•1013, − is the sign, 13 is the exponent, and 3.74 is the significand.) If printf did take some or all of the bits that encoded a double and interpreted them according to %d, it would print a number very different from the value of the floating-point number (except by exceedingly rare coincidence).
Also note that no pointers are printed or passed in printf ("\n%d %d %d %d",a,*( &a ),*b,*c );. a, *( &a ), *b, and *c are all a.
In printf ( "\n%u %u %u", &a, b, c );, the pointers are printed incorrectly. Correct code is printf("%p %p %p\n", (void *) &a, (void *) b, (void *) c);. Here I have made three changes:
%p is a correct conversion specification for printing pointers. Sometimes printing with %u will print the same value (although in decimal rather than hexadecimal), but, if that happens, it is just because pointers get passed in the same places as unsigned int, they are the same size, and the errors did not fall afoul of compiler optimization.
- The pointers are cast to
void * for printing. This ensures they are in a common form, suitable for %p, when passed.
- I moved the
\n to the end of the string instead of the beginning. C is designed for new-line characters to be at the ends of the lines instead of the starts, because, when there is a new-line character, it sends output to interactive devices immediately instead of holding it in a buffer.
%p, not%u- and you have to cast the pointer tovoid *first. You're invoking undefined behavior when you use the wrong format specifier.print_int(int x), the arguments would be converted and you couldprint_int(2.1), but for obvious reasons, it can't be done for variadic arguments. The type of the argument is determined at run-time from the%specifiers and while most compilers know about theprintfsyntax, they don't use it for compilation, only to issue warnings. Listen to these warnings.