I think I finally understand what you want, but I'm still not sure why you want it, and I suspect that you don't really need it. If you would tell us what your ultimate goal is, we might be able to tell you what you really need. That said:
You seem to be aware that
Foo* p = 0;
is defined as setting p
to be a null pointer, which may or may not actually be represented by a string of zero-bits in memory. You seem to want a way to ensure that the memory occupied by the pointer is full of zero bits, rather than whatever bit pattern represents the null pointer.
Here are two ways you might do this. The most straightforward and correct is simply:
Foo* p;
memset(&p, 0, sizeof(p));
Another, which seems to be what you were thinking of with the reinterpret_cast
, is this:
Foo* p;
int i = 0;
p = reinterpret_cast<Foo*>(i);
The reason that this works and assigning p
directly to zero does not is because only literal zeros are interpreted as the null pointer when assigned to pointers. i
contains the value zero, but is not a literal zero. The above is wrong, though, when pointers and integers aren't the same size, so a better method might be:
Foo* p;
char c[sizeof(p)] = {0};
p = reinterpret_cast<Foo*>(c);
However, this is still not correct because it is undefined behavior to access the result of a reinterpret_cast
when you're lying about the real type of the variable you cast. c
is not really a Foo*
above, so this is undefined behavior. Thus, you should use memset
to achieve this instead.
The reason you seemed to want a typedef
is so that you could have a pointer type that is automatically assigned the value 0 when created. Unfortunately, this is not possible. A typedef
can only specify a type, not an initial value. Apart from creating your own smart-pointer class to do this, the best you could do is wrap up the call to memset
in a convenience function, e.g.
template <typename T> T* zeroPointer() {
T* p;
memset(&p, 0, sizeof(p));
return p;
}
Foo* p = zeroPointer<Foo>();
Now, even given all of that, this still may not give you what you want in all cases. As GMan pointed out in his comments, it's not guaranteed that pointers are represented by numbers on all platforms, so the value of p
may not be numeric zero after this, and may not correspond to address 0 on the system, even if it is all zero-bits. A given system may not even have such a thing as an "address 0". For example, on a particular system, a pointer may be represented by a struct containing a segment address and an offset.
Finally, be aware that you will have to go to extra pains to test for this value. For example:
Foo* p = zeroPointer<Foo>();
if (p == 0) {
// Not reached if NULL is not all-zero bits, since the literal 0 in the
// comparison is interpreted as a null pointer constant
}
You would essentially have to check each bit individually. The only way to do this without invoking undefined behavior is something like this:
template <typename T> bool isZero(T& p)
{
char c[sizeof(p)];
memcpy(&c, &p, sizeof(p));
for (int i = 0; i < sizeof(p); ++i) {
if (c[i] != 0) return false;
}
return true;
}
Foo* p = zeroPointer<Foo>();
if (isZero(p)) {
// Always reached
}
This is all pretty cumbersome, because you're working against the language here. The language is trying to be helpful by giving a portable method of setting null pointers, but you want to eschew that and make up your own all-zero-bits pointer for some reason. That's why I'm convinced that whatever it is that you ultimately want to do can be done in some other way that doesn't involve fighting the language you're programming in.