Someone else mentioned container_of(), but didn't provide an explanation for this really handy macro. Let's say you have a struct that looks like this:
struct thing {
int a;
int b;
};
Now if we have a pointer to b, we can use container_of() to get a pointer to thing in a type safe fashion:
int *bp = ...;
struct thing *t = container_of(bp, struct thing, b);
This is useful in creating abstract data structures. For example, rather than taking the approach queue.h takes for creating things like SLIST (tons of crazy macros for every operation), you can now write an slist implementation that looks something like this:
struct slist_el {
struct slist_el *next;
};
struct slist_head {
struct slist_el *first;
};
void
slist_insert_head(struct slist_head *head, struct slist_el *el)
{
el->next = head->first;
head->first = el;
}
struct slist_el
slist_pop_head(struct slist_head *head)
{
struct slist_el *el;
if (head->first == NULL)
return NULL;
el = head->first;
head->first = el->next;
return (el);
}
Which is not crazy macro code. It will give good compiler line-numbers on errors and works nice with the debugger. It's also fairly typesafe, except for cases where structs use multiple types (eg if we allowed struct color in the below example to be on more linked lists than just the colors one).
Users can now use your library like this:
struct colors {
int r;
int g;
int b;
struct slist_el colors;
};
struct *color = malloc(sizeof(struct person));
color->r = 255;
color->g = 0;
color->b = 0;
slist_insert_head(color_stack, &color->colors);
...
el = slist_pop_head(color_stack);
color = el == NULL ? NULL : container_of(el, struct color, colors);