2

When i run this code it prints address of a in 1st printf, and value of a in 2nd printf.

#include <stdio.h>
int main() 
{
float a=7.999999;
float *b,*c;
b=&a;
c=b;
printf ( "\n%u %u %u", &a, b, c );
printf ("\n%f %f %f %f",a,*( &a ),*b,*c );
}

But When i change %f to %d in 2nd printf like this.

#include <stdio.h>   
int main() 
{
float a=7.999999;
float *b,*c;
b=&a;
c=b;
printf ( "\n%u %u %u", &a, b, c );
printf ("\n%d %d %d %d",a,*( &a ),*b,*c );
}

it prints random values in 2nd printf please explain why. float pointer should be printed using %f but why can't by using %d.

5
  • 1
    You're type-punning the float into an integer, which does not preserve the numerical value. Commented Dec 27, 2020 at 16:24
  • 3
    When i run this code it prints address of a in 1st printf Not necessarily. The proper format specifier to print an address is %p, not %u - and you have to cast the pointer to void * first. You're invoking undefined behavior when you use the wrong format specifier. Commented Dec 27, 2020 at 16:27
  • 3
    If you had a non-variadic function like print_int(int x), the arguments would be converted and you could print_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 the printf syntax, they don't use it for compilation, only to issue warnings. Listen to these warnings. Commented Dec 27, 2020 at 16:35
  • @EricPostpischil I agree my remark was clumsy, also because in printf %f waits for a double and not a float as I said. Commented Dec 27, 2020 at 19:38
  • All these printf's invoke the infamous Undefined Behaviour, because the conversion specifiers do not match the types of the variables passed in. So do not wonder ... Commented Dec 27, 2020 at 20:30

2 Answers 2

6

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.
Sign up to request clarification or add additional context in comments.

Comments

1

%d REQUIRES that the argument is an int value. (and this is the reason you are getting garbage)

If you want to print your floats as integers, use %0.0f instead. This will print the value rounded to the nearest integer, and with no decimals (I'm not sure now if this prints the decimal dot or not, but if it does, try the alternative %0.0g)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.