C++ – Properly Cast a `void*` to an Integer

c++castingpointers

I'm dealing with some code that uses an external library in which you can pass values to callbacks via a void* value.

Unfortunately, the previous person working on this code decided to just pass integers to these callbacks by casting an integer to a void pointer ((void*)val).

I'm now working on cleaning up this mess, and I'm trying to determine the "proper" way to cast an integer to/from a void*. Unfortunately, fixing the use of the void pointers is somewhat beyond the scope of the rework I'm able to do here.

Right now, I'm doing two casts to convert from/to a void pointer:

static_cast<int>(reinterpret_cast<intptr_t>(void_p))

and

reinterpret_cast<void *>(static_cast<intptr_t>(dat_val))

Since I'm on a 64 bit machine, casting directly ((int)void_p) results in the error:

error: cast from 'void*' to 'int' loses precision [-fpermissive]

The original implementation did work with -fpermissive, but I'm trying to get away from that for maintainability and bug-related issues, so I'm trying to do this "properly", e.g. c++ casts.

Casting directly to an int (static_cast<int>(void_p)) fails (error: invalid static_cast from type 'void*' to type 'int'). My understanding of reinterpret_cast is that it basically just causes the compiler to treat the address of the value in question as the cast-to data-type without actually emitting any machine code, so casting an int directly to a void* would be a bad idea because the void* is larger then the int (4/8 bytes respectively).

I think using intptr_t is the correct intermediate here, since it's guaranteed to be large enough to contain the integral value of the void*, and once I have an integer value I can then truncate it without causing the compiler to complain.

Is this the correct, or even a sane approach given I'm stuck having to push data through a void pointer?

Best Answer

I think using intptr_t is the correct intermediate here, since it's guaranteed to be large enough to contain the integral value of the void*, and once I have an integer value I can then truncate it without causing the compiler to complain.

Yes, for the reason you mentioned that's the proper intermediate type. By now, if your implementation doesn't offer it, you probably have more problems than just a missing typedef.

Is this the correct, or even a sane approach given I'm stuck having to push data through a void pointer?

Yes, given the constraints, it's quite sane.
You might consider checking the value fits instead of simply truncating it upon unpacking it from the void* in debug-mode, or even making all further processing of that integer use intptr instead of int to avoid truncation.

You could also consider pushing a pointer to an actual int instead of the int itself though that parameter. Be aware that's less efficient though, and opens you to lifetime issues.

Related Question