I'm working on a C project where I use a void*
variable to hold pointer values. I also need to embed some state information within the same variable. For example, I already use NULL
to indicate that the pointer does not refer to any valid memory (i.e., a "null state").
My question is:
Are there any other values—like a specific number (e.g., (void*)-1
)—that are guaranteed to represent an "invalid" or "sentinel" state in a portable way? In other words, besides NULL, are there any standard or recommended values I can store in a void* to indicate that it doesn't point to a valid object?
If not, what is the best practice for embedding extra state information in pointer variables while ensuring portability across different systems?
Any insights or examples would be greatly appreciated.
What did I try?
I attempted to call __builtin_return_address(0)
to retrieve the current function's return address. My idea was to use that address as a unique state marker in a void*
variable—essentially, to represent a specific "state" that is distinct from NULL.
What was I expecting? I expected that since __builtin_return_address(0) returns a concrete address (obtained from the stack during the function call), it could be used as a non-NULL sentinel value. In other words, I thought that because the return address is stored in memory (albeit on the stack), it might serve as a reliable indicator for a special state within the function, separate from a valid pointer or a NULL pointer.
Just use the address of any global.
char ERROR_FOO_OBJ;
#define ERROR_FOO ((void*)&ERROR_FOO_OBJ)
return ERROR_FOO;
if ( p == ERROR_FOO ) ...;
Just-beyond-an-object is a valid pointer (although not one that can be dereferenced). So while unlikely, it's possible to have a valid pointer equal to ERROR_FOO
. If it makes sense to return a pointer that points just beyond an object, you can protect yourself by using the following instead:
char ERROR_CODE_OBJS[2];
#define ERROR_FOO ((void*)&ERROR_CODE_OBJS[1])
return ERROR_FOO;
if ( p == ERROR_FOO ) ...;
Thanks to Nate Eldredge who raised this issue in the comments.
Trying to collecting possible answers. Several reserved values exist in various standards, and many in practice have constant values (if a new OS violates this rule, it would break a lot of programs, so this is unlikely to happen).
Data pointers:
Code pointers (may be different than data pointers on some platforms):
Again: unless otherwise noted, assume the actual numerical values are not standard. I've checked these on Linux but am pretty sure most have the same values on most other platforms.
Various non-system software often specifies a greater range of fake pointers, usually well within "page" size (but how big that is is highly system-dependent; 128 is probably safe in practice due to errno values).
(I am vaguely aware that Windows has special values with the high bit set, but Windows is as far from standard as possible)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With