I've been looking at this intrusive linked list implementation in C, and there is some pointer arithmetic that I cannot seem to piece together.
Firstly there is this function and macro which initiate a link node:
#define LINK_INIT(linkptr, structure, member) \
link_init(linkptr, offsetof(structure, member))
void link_init(link *lnk, size_t offset) {
lnk->next = (void*) ((size_t) lnk + 1 - offset);
lnk->prev = lnk;
}
I understand that lnk->next (void*) ((size_t) lnk + 1 - offset) is a pointer to the next struct in the linked list, but I don't understand why adding 1 allows the pointer to work still when the offset is number of bytes offsetting the member from the start of the struct. In the struct header definition the author says that the low bit is used as a sentinel to signify the end of the list, and so the lnk->next pointer can be &'d with 1 to test for the end:
// All nodes (=next) must be allocated on (at least) two-byte boundaries
// because the low bit is used as a sentinel to signal end-of-list.
typedef struct link {
struct link *prev;
void *next;
} link;
void* link_next(link *lnk) {
if ((size_t) lnk->next & 1)
return NULL;
return lnk->next;
}
I'm just wondering why this works at all? I vaguely understand allocation boundaries but I guess not enough to see why this works.
// because the low bit is used as a sentinel to signal end-of-list.sounds very odd. I don't believe you can (ab)use a pointer this way. - πάντα ῥεῖsize_t. At the very least, cast to something sensible, likeintptr_t. - user3386109