9

So I'm using this C library in my C++ app, and one of the functions returns a void*. Now I'm not the sharpest with pure C, but have heard that a void* can be cast to pretty much any other *-type. I also know that I expect a float at the end somewhere from this function.

So I cast the void* to a float* and dereference the float*, crash. darn!. I debug the code and in gdb let it evaluate (float)voidPtr and low and behold the value is what I expect and need!

But wait, it's impossible to the same during compile time. If I write float number = (float)voidPtr; it doesn't compile, which is understandable.

So now the question, how do I get my float out of this fricking void*?

EDIT: Thanks to H2CO3 this was solved, but I see lots of answers and comments appearing and dissappering not believing that I could do (float)voidPtr in gdb. here is the screenshot.

enter image description here

xNidhogg
  • 331
  • 1
  • 4
  • 12
  • 2
    Of course, a better solution is not ending up in a situation like this to begin with. –  Mar 09 '13 at 17:24
  • 3
    @delnan, so OP should give up on an entire library because it uses void pointers? – Corey Ogburn Mar 09 '13 at 17:25
  • 1
    @CoreyOgburn No, I'm talking about a non-pointer being interpreted as a void pointer. `void *` is perfectly fine in some cases, but in OP's case, someone somewhere screwed up. Perhaps OP is using the library wrong. –  Mar 09 '13 at 17:27
  • 1
    Maybe the function can return a pointer or an actual value, depending on how it's invoked. Without seeing the library, we can't really judge. – James M Mar 09 '13 at 17:28

2 Answers2

17

Try using pointers:

void *theValueAsVoidPtr = // whatever

float flt = *(float *)&theValueAsVoidPtr;
  • 9
    Note that this assumes that `sizeof(float) == sizeof(void *)` which may not be true, and in that case this invokes undefined behavior. –  Mar 09 '13 at 17:24
  • 2
    This works, I was missing the additional &. Not sure what or why exactly this happens now, but it works. thanks. – xNidhogg Mar 09 '13 at 17:32
  • 2
    @xNidhogg Explanation: the type safety of pointers is weaker than non-pointers. You can't cast `void *` to `float`, but you can cast `void **` to `float *`. Now when you do that, and dereference the address of the `theValueAsVoidPtr` variable, then you get the *contents* of that variable, just in another type - this is called type punning. See the [line marked with "evil floating-point bit level hacking"](http://en.wikipedia.org/wiki/Fast_inverse_square_root#Overview_of_the_code). –  Mar 09 '13 at 17:33
  • This will work on many compilers but violates the type aliasing rules. – zwol Mar 10 '15 at 21:03
9

If I understand correctly, your library is returning a float value in a variable whose declared type is void *. The safest way to get it back out again is with a union:

#include <assert.h>
static_assert(sizeof(float) == sizeof(void *));

union extract_float {
    float vf;
    void * vp;
};

float foo(...)
{
    union extract_float ef;
    ef.vp = problematic_library_call(...);
    return ef.vf;
}

Unlike the approach in the accepted answer, this does not trigger undefined behavior.

zwol
  • 135,547
  • 38
  • 252
  • 361
  • 1
    *"The safest way to get it back out again is with a union..."* - Not in C++. Accessing an inactive union member is undefined behavior. I believe the safest way is a `memcpy`. – jww Mar 14 '18 at 21:31
  • @jww That is a bug in the C++ standard that should have been fixed over a decade ago. Any C++ compiler that doesn't implement the C99+errata semantics for unions is also buggy. – zwol Mar 15 '18 at 15:20