Reputation: 23
I was looking over the source code for the "tfind" function from the "search.h" C library and I stumbled upon this line:
#define DEREFNODEPTR(NP) (node)((uintptr_t)(*(NP)) & ~((uintptr_t) 0x1))
This is how it's used:
/* Find datum in search tree.
KEY is the key to be located, ROOTP is the address of tree root,
COMPAR the ordering function. */
void *
__tfind (const void *key, void *const *vrootp, __compar_fn_t compar)
{
node root;
node *rootp = (node *) vrootp;
if (rootp == NULL)
return NULL;
root = DEREFNODEPTR(rootp);
CHECK_TREE (root);
while (DEREFNODEPTR(rootp) != NULL)
{
root = DEREFNODEPTR(rootp);
int r;
r = (*compar) (key, root->key);
if (r == 0)
return root;
rootp = r < 0 ? LEFTPTR(root) : RIGHTPTR(root);
}
return NULL;
}
So, why is one's complement needed in this case?
Thank you for your time and consideration.
Upvotes: 1
Views: 95
Reputation: 70382
It is likely the case that the implementation assumes the node pointers are to nodes that are always at least 2 byte aligned. This means that the least significant bit will always be 0 for a valid node pointer. This allows the bit to be "used" to store state (such as whether or not it has been visited before, or whether it is a red or black node, or some other thing...).
The macro clears the LSB before accessing the value as a pointer. There is no one's complement requirement.
Upvotes: 5