2

I need a simple way to convert a pointer to an int, and then back to the pointer. I need it as an int for portability, since an int is easier to carry around in my project than a pointer.

Start player and return pointer:

SoundPlayer* player = new FxPlayerTiny(); return (int)player; // this works, but is it correct? 

Stop player using pointer int:

FxPlayerTiny* player = static_cast<FxPlayerTiny*>((int*)num); // this gives me an error FxPlayerTiny* player = (FxPlayerTiny*)((int*)obj); // this works, but is it correct? delete player; 
16
  • 5
    Er, how is int easier to carry around? And no that code isn't safe. Commented Mar 24, 2013 at 18:27
  • 3
    If you really really have to cast to something opaque, at least use a void*. Commented Mar 24, 2013 at 18:29
  • Why is an int easier to use than a pointer? That just sounds wrong. Also, there are no guarantees a whole pointer will fit in an int. C provides intptr_t (and most implementations of C++ also provide it) that is an integer type guaranteed to be large enough to hold a pointer. Use reinterpret_cast to switch between the two. Commented Mar 24, 2013 at 18:33
  • @James: There's no guarantee that intptr_t and uinptr_t exist; on an implementation where pointers are bigger than the widest supported integer, they won't. But I've never heard of such an implementation. Also, those types were introduced in C99, so older C compilers (and Microsoft's) may not support them. Commented Mar 24, 2013 at 18:34
  • 1
    Fix your project so it's capable of dealing with pointers directly. Commented Mar 24, 2013 at 18:35

2 Answers 2

9

The best thing to do is to fix your project so it can deal with pointers. Integers and pointers are two different things. You can convert back and forth, but such conversions can lose information if you're not careful.

Converting a pointer value to int and back again can easily lose information, depending on the implementation and the underlying platform. For example, there are systems on int is smaller than a pointer. If you have 32-bit ints and 64-bit pointers, then converting a pointer to an int and back again will almost certainly give you an invalid pointer.

It's very likely that long or unsigned long is wide enough to hold a converted pointer value without loss of information; I've never worked on a system where it isn't. (Personally, I tend to prefer unsigned types, but not for any really good reason; either should work equally well.)

So you could write, for example:

SoundPlayer* player = new FxPlayerTiny(); return reinterpret_cast<unsigned long>player; 

and convert the unsigned long value back to a pointer using reinterpret_cast,SoundPlayer*>.

Newer implementations provide typedefs uintptr_t and intptr_t, which are unsigned and signed integer types guaranteed to work correctly for round-trip pointer-to-integer-to-pointer conversions. They were introduced in C99, and optionally defined in the <stdint.h> header. (Implementations on which pointers are bigger than any integer type won't define them, but such implementations are rare.) C++ adopted them with the 2011 standard, defining them in the <cstdint> header. But Microsoft Visual C++ does support them as of the 2010 version.

This guarantee applies only to ordinary pointers, not to function pointers or member pointers.

So if you must do this, you can write:

#include <cstdint> SoundPlayer* player = new FxPlayerTiny(); return reinterpret_cast<std::uintptr_t>player; 

But first, consider this. new FxPlayerTiny() gives you a pointer value, and you're going to want a pointer value. If at all possible, just keep it as a pointer. Converting it to an integer means that you have to decide which of several techniques to use, and you have to keep track of which pointer type your integer value is supposed to represent. If you make a mistake, either using an integer type that isn't big enough or losing track of which pointer type you've stored, the compiler likely won't warn you about it.

Perhaps you have a good reason for needing to do that, but if you can just store pointers as pointers your life will be a lot easier.

Sign up to request clarification or add additional context in comments.

2 Comments

Microsoft Visual C++ has supported uintptr_t, intptr_t, and ptrdiff_t (their always forgotten partner) since at least the 2008 release, probably longer. :)
ptrdiff_t has been standard since 1989, but it's nice to know that that they support [u]intptr_t as well.
1

It is not recommended to use an int for portability, especially because sizeof (int) and sizeof (void*) could differ (for example when compiling for Windows x64). If ints are needed for a user interface, it maybe would be better to use a table of pointers and accessing them via indices.

However, if you want to convert an pointer to an integer and vice versa a simple conversion is enough but it's just the same, if sizeof *int) == sizeof (void*).

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.