Is it safe to cast an int to void pointer and back to int again?
In 开发者_StackOverflow社区C and/or C++: is it safe to cast an int to void pointer and back to int again?
Based on the question "C++: Is it safe to cast pointer to int and later back to pointer again?".
In most modern-day commonplace machines, probably.
However, I'd bet that there is some obscure compiler or configuration (say, a 16-bit addressed machine that uses 32-bit integer arithmetic) where that is not the case.
A uintptr_t is guaranteed to hold both, though, so use that type if you want to.
Here is an example where converting a pointer to an integer may not result in the same pointer when converting the integer to a pointer.
Given an architecture which has 24 bit addresses and uses two 16-bit quantities to describe the location. Let one quantity be the SEGMENT and the other OFFSET. A location is designated by the notation SEGMENT:OFFSET.
The actual 24-bit (Physical) address is calculated by:
address = segment * 16 + offset.
Using this notation, there can be more than one SEGMENT:OFFSET pair that describe the same physical address.
When converting to an integer, a 32-bit (unsigned) quantity is used (to simplify internal calculations in the processor). The problem is how to convert the physical address into the same SEGMENT::OFFSET that was used in the creation of the physical address.
A generic equation for converting integer to pointer is:
offset = address & 0xFFFF; // Mask off high order bits, keep lower 16.
segment = address >> 16; // Shift address right 16 bits, zero fill.
Although the physical address of this new segment and offset is equal to the physical address of the original SEGMENT:OFFSET, the segments and offsets are not guaranteed to be the same.
To optimize code, there are processor instructions that use relative addressing in a segment. These instructions may get messed up when the SEGMENT value changes due to conversion from a physical address.
In this scenario, converting from a pointer to an integer is possible. HOWEVER, converting from the integer to the pointer IS STRONGLY DISCOURAGED. Hard to debug errors could occur during run-time.
Bonus question: Can you name the actual architecture?
Why would you want to do this?
Reply for C, I don't know enough about C++ for that: No, behavior is not defined to cast an int
to void*
. First of all you should always use uintptr_t
if you have it for such a thing. Using int
is an abuse.
Then, C does not guarantee anything if your uintptr_t
doesn't come from a valid address. It only guarantees the other way round. Don't do it.
Edit: Here is the relevant part of the C99 standard. As you can see all alarms can go off...
An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation
The last is particularly embarrassing since this means that the pointer value that is such obtained can not be used anymore, until it is overwritten:
Certain object representations need not represent a value of the object type. If the stored value of an object has such a representation and is read by an lvalue expression that does not have character type, the behavior is undefined. ... Such a representation is called a trap representation.
No. A void pointer is no different from any other pointer with respect to size. Hence it will run into exactly the same types of issues as other pointer types.
It's implementation defined just like the last question and for the same reason. It's less likely to result in misbehavior but it's still implementation defined.
No. There might be certain circumstances where it appears to work for a certain compiler&settings, and then two years later you spend weeks debugging that something changed and the conversion no longer works as expected.
If you just design your code in a way that doesn't need this sort of behavior (best case avoids use of such conversion at all, worst case use char[]
) then you won't have to worry about obscure bugs in the future.
Not necessarily. Depends on the size of a pointer. Why would you want to do this?
If the range of your integers is fairly small, you could always do something like:
static const char dummy[MAXVAL];
and then use dummy+i
as a way of encoding i
as a pointer. This is 100% portable. If you only care that it's 99% portable, you could use (char *)0 + i
.
精彩评论