views:

239

answers:

3

I know this is wrong and gcc will give you a warning about it, but why does it work (i.e. the numbers are printed correctly, with some rounding difference)?

int main() {
   float *f = (float*) malloc(sizeof(float));
   *f = 123.456;
   printf("%f\n", *f);
   printf("%f\n", f);
   return 0;
}

Edit: Yes, I'm using gcc with a 32-bit machine. I was curious to see what results I'd get with other compilers.

I meddled with things a little more following Christoph's suggestion:

int main() {
   float *f = (float*) malloc(sizeof(float));
   *f = 123.456;
   printf("%f\n", f); // this
   printf("%f\n", *f);
   printf("%f\n", f); // that
   return 0;
}

This results in the first printf printing a value different from the last printf, despite being identical.

+1  A: 

The numbers aren't printed correctly for me.

Output:

123.456001
0.000000

I'm using VC++ 2009.

Jacob
+1  A: 

printf has no knowledge about actual arguments type. It just analyzes format string and interprets data on stack accordingly.

By coincidence (more or less =)) pointer to float has the same size as float (32 bit) on your platform, so stack is balanced after removing this argument from it.

On other platforms or with other data types this may not work.

elder_george
+9  A: 

Reorder the printf() statements and you'll see it won't work any longer, so GCC definetly doesn't fix anything behind your back.

As to why it works at all: Because of the default argument promotion of variable arguments, you'll actually pass a double with your first call. As pointers on your system seem to be 32bit, the second call only overwrites the lower half of the 64bit floating point value.

In regards to your modified example:

  • the first call will print a double precision value where the higher 32bits are garbage and the lower the bit value of the pointer f
  • the second call prints the value of *f promoted to double precision
  • the third call prints a double precision value with the higher 32bits coming from (double)*f (as these bits still remain on stack from the last call); as in the first case, the lower bits will again come from the pointer f
Christoph