data-structures · intermediate · ~15 min
Implement intrusive circular linked lists and recover parent structs via container_of.
The Linux kernel uses intrusive doubly-linked lists (struct list_head) embedded directly inside domain structures. The offsetof / container_of idiom recovers the parent container pointer from an embedded node pointer without separate memory allocations.
Given the intrusive node:
typedef struct ListNode {
struct ListNode *next;
struct ListNode *prev;
} ListNode;
typedef struct {
int id;
char name[32];
ListNode node; // embedded intrusive node
} UserRecord;
Implement list operations and container recovery:
void list_init(ListNode *head);
void list_push_tail(ListNode *head, ListNode *new_node);
UserRecord *user_from_node(ListNode *n);
list_init:head->next = head and head->prev = head (circular empty list).list_push_tail:new_node right before head (i.e. at the tail):
new_node->next = head; new_node->prev = head->prev; head->prev->next = new_node; head->prev = new_node;user_from_node:n == NULL, return NULL.node member inside UserRecord using offsetof(UserRecord, node).(char *)n and cast to UserRecord *.UserRecord *.ListNode head;
list_init(&head);
UserRecord u = { .id = 42, .name = "Alice" };
list_push_tail(&head, &u.node);
UserRecord *found = user_from_node(head.next); // found->id == 42
head, new_node, n: ListNode pointers.
Returns pointer to enclosing UserRecord struct.
Must use offsetof from stddef.h to compute container offset.
#include <stddef.h>
typedef struct ListNode {
struct ListNode *next;
struct ListNode *prev;
} ListNode;
typedef struct {
int id;
char name[32];
ListNode node;
} UserRecord;
void list_init(ListNode *head) {
(void)head;
}
void list_push_tail(ListNode *head, ListNode *new_node) {
(void)head; (void)new_node;
}
UserRecord *user_from_node(ListNode *n) {
(void)n;
return NULL;
}
Hardcoding member offsets instead of using offsetof; pointer arithmetic without char* cast.
Empty list has head->next == head; NULL node returns NULL.
Solve this exercise in the browser editor — compile and run against the test harness, no setup required.