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?
I think using
intptr_t
is the correct intermediate here, since it's guaranteed to be large enough to contain the integral value of thevoid*
, 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.
Based on your question, I am assuming that you call a function in some library, passing it a void*
, and at some point later in time, it calls one of your functions, passing it that same void*
.
There are basically two possible ways to do this; the first is through explicit casting, as you showed in your current code.
The other, which Deduplicator alluded to, is a little less efficient, but allows you to maintain control of the data, and possibly modify it between when you call the library function, and when it calls your callback function. This could be achieved with code similar to this:
void callbackFunction(void* dataPtr){
int data = *(int*)dataPtr;
/* DO SOMETHING WITH data */
delete dataPtr;
}
void callLibraryFunction(int dataToPass){
int* ptrToPass = new int(dataToPass);
libraryFunction(ptrToPass,callbackFunction);
}
Which one you should use depends on what you need to do with the data, and whether the ability to modify the data could be useful in the future.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With