-->

Which dummy pointer values are okay

2019-08-21 20:11发布

问题:

This is something that's been on my mind for a long time. Every once so often i see people use 1, or -1 as a dummy value for a pointer. To safe the need of a different variable.

Is it okay to use pointers like this? I suppose -1 is okay. But is it also okay to use other negative numbers? And can I be sure 1 isn't a used memory location? And if so, up to which value can i use memory pointers.

P.s. I'm aware storing other data especially positive values in pointers, is very, very bad practice. But I'm just wondering what would be the consequences in any real life situation.

回答1:

It depends on your compiler and (mostly) OS -- on most operating systems there are ranges of addresses that can never be valid. So on such an OS, it is safe to use such addresses as 'magic' values for a pointer that will never compare as equal to any valid object. As long as you never dereference them they should be fine -- and even if you do dereference it, the OS may define the behavior (generally throwing a particular signal).

A more portable alternative is to create 'dummy' global objects and use pointers to them as your special tags. No other valid object pointer will ever compare as equal to the dummy object pointer, and the extra overhead for the dummy object is minimal.



回答2:

I bet your compiler warns when you do this? That in itself should tell you that it is bad and should be avoided.

Lots of old crusty code has guards against NULL (or nullptr) for values. You place a -1 in there, which turns into an unsigned 0xffffffff address (32-bit land) into that pointer and it will merrily run though all sorts of things you don't want it to run through. Best case is an immediate access violation / seg fault. Worst case is no one notices and things go out of wack 2 months later and you are found as the, well... 'not smart person' who illegally placed a non-pointer value into a pointer and blew things up. Jobs can be lost for mistakes like this.

As an aside, why would 'people' want to use 1 or -1 in a pointer? Drop nullptr, NULL, or whatever your language supports in there and be done with it. Otherwise put a valid pointer in there and call it good.



回答3:

The only pointer values you can portably use are pointers to objects that currently exist and null pointers. (I'm ignoring function pointers and member pointers.)

The purpose of the null pointer is to have a pointer value that doesn't point to any object, and that compares unequal to any pointer that does point to an object. The language only provides one such pointer value for each pointer type.

Sometimes it can be convenient to have more than one distinguished pointer value.

You can define such values yourself -- for example:

const some_type* foo = reinterpret_cast<some_type*>(-1);
const some_type* bar = reinterpret_cast<some_type*>(-2);

Strictly speaking, using either value, even without dereferencing it, has undefined behavior. (I know that's the case for C; I think it's also true for C++.) But if you happen to know that those values are distinct from any pointers that point to actual objects, and that comparisons to them behave as expected, then you can get away with it.

There's some precedent for this in the C standard library. <signal.h> defines three macros for signal handler function pointers, SIG_DFL, SIG_ERR, and SIG_IGN. In some implementations these are defined as the constants -1, 0, and 1 cast to the appropriate pointer type. Those definitions are not portable -- but since they're part of the implementation itself, they don't have to be. The only requirement is that they must compare unequal to any pointer to a user-defined function. (In the implementation I'm using, SIG_DFL happens to be a null pointer; that's not required.)

If a library defines such a pointer, feel free to use it. If it fails, it's a bug in the library. If you want to define such a pointer yourself, be careful, and understand that it might not work correctly on all implementations.

An alternative is to define a static object of the appropriate type, and use a pointer to that object:

static some_type foo_obj;
static some_type bar_obj;
const some_type* foo = &foo_obj;
const some_type* bar = &bar_obj;

This is portable and it gives you pointer values that are guaranteed to compare unequal to the null pointer and to any pointers to user-defined objects.