1

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.

  • 1
    seems that the macro just ensures that the address is even. – Jean-François Fabre Oct 16 '17 at 19:42
  • 3
    It's masking out the low bit from the address to obtain the "real" address. I suspect it is using the low bit of the pointer to tag it in some way; this is done not so rarely as pointers to `struct` containing pointers are generally aligned on word boundaries, so the low bits of the pointer can be used to carry extra information "for free". You can get a bit of perspective on this custom [on Wikipedia](https://en.wikipedia.org/wiki/Tagged_pointer). – Matteo Italia Oct 16 '17 at 19:43
  • 1
    How do you know it is meant to be one's-complement? The `~` is often used to create a mask without knowing how many bits are in the type. So `~1` would be `F.....FE`. – Weather Vane Oct 16 '17 at 19:46

1 Answers1

5

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.

jxh
  • 69,070
  • 8
  • 110
  • 193