The Linux kernel's implementation of a linked list is contained in a header file called list.h. (The version linked is modified slightly to remove dependencies on other kernel headers so that the file can be used in userspace.) You can download the file to your projects' source directory, and include it in a C source file as:
#include "list.h"
The general idea with list.h is that we create lists where all elements are the same type of struct, and we embed the list within the struct.
Let's say we have a struct person
:
struct person {
char *name;
int age;
};
To chain this struct in a list, we embed list.h's
struct list_head
:
struct person {
struct list_head list;
char *name;
int age;
};
If we examine list.h, we will see that struct list_head
is defined as
struct list_head {
struct list_head *prev, *next;
};
In other words, it represents a node in a doubly-linked list. For the head
of the list we simply use a bare
struct list_head
:
one that is not embedded in a
struct person
.
The linked list implementation relies on a few clever macros to go from
a "pointer to the embedded struct list
" to
a "pointer to the struct that contains it" (the
struct person
). These macros are used internally within
list.h: it is extremely rare that you will use them directly,
but it is interesting to see how they work:
#ifndef offsetof
#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER)
#endif
#define container_of(ptr, type, member) \
({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); \
})
The header file list.h defines a lot of functions; the most common ones are:
The following program shows the basic usage of a list.
The following program implements a stack:
The following program implements a queue: