tags:

views:

239

answers:

8

Is it safe to cast pointer to int and later back to pointer again?

How about if we know if the pointer is 32 bit long and int is 32 bit long?

+12  A: 

No.

For instance, on x86-64, a pointer is 64-bit long, but int is only 32-bit long. Casting a pointer to int and back again makes the upper 32-bit of the pointer value lost.

KennyTM
Well, is it safe to cast if it is known that the pointer is 32-bit long?
hasdf
@RichN - my understanding is that only minimum ranges are standardized. For Visual C++ for example, size of int is the same on 32- and 64-bit platforms - 64-bit int is defined as __int64. See http://msdn.microsoft.com/en-us/library/296az74e(VS.80).aspx for details.
Steve Townsend
@hasdf technically i'd imagine that would depend on the implementation, but i'd expect most implemenatations to do what you want if the sizes where the same. what you can definitely do is cast to/from an appropriate sized array of chars. of course why you want to do this is also important cos there could be even more UB lurking in what you are trying to use this for.
jk
@hasdf Well, then you limit the portability of your app.@RichN I guess sizeof(int) depends on the compiler - see http://stackoverflow.com/questions/589575/c-size-of-int-long-etc
Sundar
@jk: No, the standard specifies that you get the original value back if the integer type is large enough. The only problem is finding a type large enough.
Mike Seymour
@hasdf: Use an `intptr_t` if you really need to cast to an arithmetic type.
KennyTM
+1  A: 

Absolutely not. Doing some makes a bad assumption that the size of an int and a pointer are the same. This is almost always no the case on 64 bit platforms. If they are not the same a precision loss will occur and the final pointer value will be incorrect.

MyType* pValue = ...
int stored = (int)pValue; // Just lost the upper 4 bytes on a 64 bit platform
pValue = (MyType*)stored; // pValue is now invalid 
pValue->SomeOp();  // Kaboom
JaredPar
+1  A: 

Is it safe? Not really.

In most circumstances, will it work? Yes

Certainly if an int is too small to hold the full pointer value and truncates, you won't get your original pointer back (hopefully your compiler will warn you about this case, with GCC truncating conversions from pointer to integers are hard errors). A long, or uintptr_t if your library supports it, may be better choices.

Even if your integer type and pointer types are the same size, it will not necessarily work depending on your application runtime. In particular, if you're using a garbage collector in your program it might easily decide that the pointer is no longer outstanding, and when you later cast your integer back to a pointer and try to dereference it, you'll find out the object was already reaped.

Jack Lloyd
A: 

Use uintptr_t from "stdint.h" or from "boost/stdint.h". It is guaranteed to have enough storage for a pointer.

Maxim Yegorushkin
That'll be `<boost/cstdint.hpp>`
Mike Seymour
A: 

No it is not. Even if we rule out the architecture issue, size of a pointer and an integer have differences. A pointer can be of three types in C++ : near, far, and huge. They have different sizes. And if we talk about an integer its normally of 16 or 32 bit. So casting integer into pointers and vice-verse is not safe. Utmost care has to be taken, as there very much chances of precision loss. In most of the cases an integer will be short of space to store a pointer, resulting in loss of value.

M LOHIT
A: 

Yes and no.

The language specification explicitly states that it is safe (meaning that in the end you will get the original pointer value) as long as the size of the integral type is sufficient to store the [implementation-dependent] integral representation of the pointer.

So, in general case it is not "safe", since in general case int can easily turn out to be too small. In your specific case it though it might be safe, since your int might be sufficiently large to store your pointer.

Normally, when you need to do something like that, you should use the intptr_t/uintptr_t types, which are specifically introduced for that purpose. Unfortunately, intptr_t/uintptr_t are not the part of the current C++ standard (they are standard C99 types), but many implementations provide them nevertheless. You can always define these types yourself, of course.

AndreyT
A: 

If your going to be doing any system portable casting, you need to use something like Microsofts INT_PTR/UINT_PTR, the safety after that relies on the target platforms and what you intend doing to the INT_PTR. generally for most arithmatic char* or uint_8* works better while being typesafe(ish)

Necrolis
A: 

In general, no; pointers may be larger than int, in which case you there's no way to reconstruct the value.

If an integer type is known to be large enough, then you can; according to the Standard (5.2.10/5):

A pointer converted to an integer of sufficient size ... and back to the same pointer type will have its original value

However, in C++03, there's no standard way to tell which integer types are large enough. C++0x and C99 (and hence in practice most C++03 implementations), and also Boost.Integer, define intptr_t and uintptr_t for this purpose. Or you could define your own type and assert (preferably at compile time) that it's large enough; or, if you don't have some special reason for it to be an integer type, use void*.

Mike Seymour