Is it a good idea to use intptr_t
as a general-purpose storage (to hold pointers and integer values) instead of void*
? (As seen here: http://www.crystalspace3d.org/docs/online/manual/Api1_005f0-64_002dBit-Portability-Changes.html)
For what I've already read:
int
->void*
->int
roundtrip is not guaranteed to hold original value; I guessint
->intptr_t
->int
will do- pointer arithmetics on both
void*
andintptr_t
require casts, so none gets advantage here void*
means less explicit casts when storing pointers,intptr_t
means less casts when storing integer valuesintptr_t
requires C99
What else should I take into consideration?
No, you can't be guaranteed that any particular type is a reasonable way of storing both pointers and integers, and besides, it makes your code confusing. There is a better way.
If you want to store an integer and a pointer in the same object, the clean and portable method is to use a union:
This is portable and allows you to store both sorts of things in the size of storage needed for the larger of the two. It is guaranteed to always work.
No.
intptr_t
is not guaranteed to exist. First, as you note, it was introduced in C99. Second, implementations are not required to have an integer type big enough to hold converted pointer values without loss of information.Converting an
int
tointptr_t
and back is unlikely to lose information but there's no actual guarantee thatintptr_t
is wider thanint
.If you want to store pointer values, store them in pointer objects. That's what pointer objects are for.
Any pointer to an object or incomplete type can be converted to
void*
and back again without loss of information. There is no such guarantee for pointers to functions -- but any pointer-to-function type can be converted to any other pointer-to-function-type and back without loss of information. (I'm referring to the C standard; I think POSIX provides some additional guarantees.)If you want to store either an integer or a pointer value in the same object, the first thing you should do is re-think your design. If you've already done so, and concluded that you really do want to do this, consider using a union (and keeping careful track of what kind of value you've stored most recently).
There are APIs that use a
void*
argument to allow arbitrary data to be passed; see, for example, the POSIXpthread_create()
function. This can be abused by casting an integer value tovoid*
but it's safer to pass the address of an integer object.