0

I have a function that returns an unsigned long that is actually a float.

We'll call that function unsigned long foo()

When I make a call to printf like this:

printf("%f", foo());

it will always print out 0.00000

but when I cast it like this:

unsigned long bar = foo();
printf("%f", *((float *)(&bar)));

it outputs the float correctly.

Printing with "%x" I can see that the binary representations are different. Surprisingly the unsigned long version looks more like an actual floating point representation (41ba019a vs 40000000)

I double checked on my system that the size of unsigned long and float are the same.

So my question is:

How can casting the pointer like this change the value of what is being pointed to?

Edit: The relevant part of foo() is essentially

unsigned long foo()
{
  float a = 22.4;
  return *(unsigned long *)(&a) ;
}
Clifford
  • 88,407
  • 13
  • 85
  • 165
rtpax
  • 1,687
  • 1
  • 18
  • 32
  • You're not showing us the most important thing of all. Let's see `foo()`. – Carey Gregory Jul 17 '17 at 17:08
  • The value of the unsigned long was cast from a floating point to begin with. The function can return different types depending on the argument. – rtpax Jul 17 '17 at 17:08
  • So? Let's see the pertinent part. – Carey Gregory Jul 17 '17 at 17:10
  • 1
    Isn't that because a float, when passed to a function, is first promoted to a double, so printf expects a double to be printed as a float? Since foo does not return a float, the transformation is not perfomed, hence the 0.0000. – Paul Ogilvie Jul 17 '17 at 17:17
  • This is a really bad code. If you want the function to return different types, make it work with a `union` of all of the possible types and return it. Don't reinterpret like this. It will help to avoid issues like this and other potential UBs. – Eugene Sh. Jul 17 '17 at 17:18
  • @Paul Ogilvie You are correct, printing with "%llx" I can see the parts lining up as one would expect. If you post an answer I will accept unless there is a better one – rtpax Jul 17 '17 at 17:24

1 Answers1

2

That is because a float, when passed to a function, is first promoted to a double, so printf expects a double to be printed. Since foo does not return a float, the transformation is not perfomed, hence printf finds something else as parameter.

Paul Ogilvie
  • 25,048
  • 4
  • 23
  • 41
  • Promotion of `float` to `double` is specific to variadic functions (such as `printf()`), not all functions. – Clifford Jul 17 '17 at 17:58
  • @Clifford, do you have a reference (just for my curiosity)? I didn't know. – Paul Ogilvie Jul 17 '17 at 18:27
  • 1
    ... ok, that's not the whole story. `float` arguments to functions without prototypes are also promoted. For example if you declared `void fn()` but called `fn( 1.0f )`, the argument would be promoted to `double` too. But those are exceptions to the common case where functions are fully prototyped. https://stackoverflow.com/questions/1255775/default-argument-promotions-in-c-function-calls. Note does not apply to C++ where `void fn()` is the same as `void fn( void )`. – Clifford Jul 17 '17 at 18:44