Properly casting a `void*` to an integer in C++

33.4k Views Asked by At

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?

4

There are 4 best solutions below

1
On 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.

0
On

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

Well, regarding correct and sane its seriously debatable, especially if you are the author of the code taking the void* in the interface.

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, that's the right type to use with a reinterpret_cast<intptr_t>, but you'll need to be sure, that a intptr_t pointer type has been passed in, and the address is valid and doesn't go out of scope.


It's not so unusual to stumble over this problem, when interacting with API's, and these are offering callbacks, that allow you to pass in user-data, that will be handled transparently by them, and never are touched, besides of your entry points1.

So it's left up to the client code being sure about how that void* should be re-interpreted safely.


1) A classical example for this kind of situation, is the pthread_create() function

0
On

You have little choice but to use static and reinterpret cast here. Casting to an int will result in loss of precision, which is never ideal. Explicitly casting is always best avoided, because sooner or later what is being casted can change and there will be no compiler warnings then. But in this case you understandably have no choice. Or do you?

You can change the callback definitions on your side to be intptr_t or long int rather than void*, and it should then work and you will not have to do any type casts...

2
On

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.