问题
I have seen and used this many times is C++, specially in various thread implementations. What I wonder is if there are any pitfalls/ issues of doing this? Is there any way that we could run in to an error or undefined condition when we are casting to void* and back again? How should we resolve such issues if there are any?
Thank you.
回答1:
What I wonder is if there are any pitfalls/ issues of doing this?
You need to be absolutely sure while casting the the void*
back to the particular type, if you don't, you end up with an Undefined behavior and a potential disaster. Once you use void *
you lose type safety.It is difficult to keep track of what type a void *
is actually pointing to, there is no way to guarantee or determine that it indeed points to the type to which you are going to typecast it back to.
Is there any way that we could run in to an error or undefined condition when we are casting to void* and back again?
Yes, the scenario mentioned in #1
.
How should we resolve such issues if there are any?
Avoid using void *
in C++ completely, instead use templates and inheritance.
In C you might absoultely need it in certain situations but try to keep its use to a minimum.
Bottomline,
C/C++ allows you to shoot yourself in foot, it is up to you to do or not do so.
回答2:
I have not seen casting to void* much in C++. It was a practice in C that was actively avoided in C++.
Casting to void* removes all type safety.
If you use reinterpret_cast
or static_cast
to cast from a pointer type to void*
and back to the same pointer type, you are actually guaranteed by the standard that the result will be well-defined.
The hazard is that you may cast a void*
to the wrong type, since you are no longer assured of what the correct type was.
回答3:
The only thing the standard grants is that, given A* pa
, (A*)(void*)pA == pA
.
A a consequence
void* pv = pA;
A* pA2 = (A*)pv;
pA2->anything ...
will be te same as pA->anything ...
Everything else is "not defined", ad -in fact- is somehow implementation dependent.
Based on my experience, here are some known pitfalls:
- Consider
A
derived formB
,pA
andpB
to beA*
andB*
.pB=pA
makespB
to point to the base ofA
. That doesnt mean thatpB
andpA
are the same address. hencepB = (B*)(void*)pA
can actually point anywhere else into A (although single inheritance objects are commonly implemented sharing the same origin, so it apparently works fine) - The same is viceversa: Assuming
pB
actually is pointing to anA
,pA = (A*)(void*)pB
don't necessarily point correctly to the A object. The correct way ispA = static_cast<A*>(pB);
- If the above points can work with the most of single inheritance implementations, will never work with multiple imheritance for bases other than the first: consider
class A: public Z, public B { ... };
ifZ
is not empty, given anA
, theB
subcomponent will not have the same A address. (and multiple inheritance in C++ is everywhere an iostream is) - Sometimes things depend also on the platform:
(char*)(void*)pI
(wherepI
points to an integer) will not be the same as "*pI
if*pI
in(-128..+127)" (it will be only on little endian machines)
In general don't assume conversion between types works just changing the way an address is interpreted.
回答4:
I know a lot of functions within driver etc. using void pointers to return data to the caller, the schema is mostly the same:
int requestSomeData(int kindOfData, void * buffer, int bufferSize);
This function can take different data types as parameter. What they do is using bufferSize as a parameter to avoid writing to memory places they should not write to. If the bufferSize does not match or is smaller than the data that shall be returned, the function will return an error code instead.
Anyway: Avoid using them or think threefold before writing any code.
来源:https://stackoverflow.com/questions/12275321/casting-to-void-and-back-to-original-data-type