General linked list in C Language
In operating system programming, C is often used, but C is extremely painful to use, unlike C ++, which has a convenient STL template library.
In the Linux kernel, there is a set of magical universal linked list structures for convenient use and management of various types of data. Let's take a look at the C data structure in the kernel today.
For more information, see [Linux kernel linked list]
First of all, our goal is to build a circular double-stranded table structure, why is it a double-stranded table, but also a loop, of course, from the ease of use, the double-stranded table can easily learn about its previous element, it is more convenient to manage data in the kernel.
The general structure is like this:
Implementation Mechanism
First, define a list_node structure to save the node information of the linked list:
/*** @ Brief linked list node Structure */typedef struct _ list_node {struct _ list_node * next; struct _ list_node * prev;} list_node;
Then we use a data storage structure. For example, we need to use an int-type linked list, which is defined as follows:
/*** @ Brief data storage structure */typedef struct _ Int_List {list_node node; int data;} Int_List;
This is not the same as the implementation of our traditional linked list. Of course, our classic C-language linked list stores data in the linked list:
/*** @ Brief linked list node Structure */typedef ElementType int; typedef struct _ list_node {struct _ list_node * next; struct _ list_node * prev; ElementType data;} list_node;
However, such an implementation will inevitably lead to repeated definitions of the linked list structure, making it difficult to implement generics. Another idea may be to implement ElementType into a void * pointer, and then force type conversion during use, but this will inevitably lead to repeated type conversion, and its use is relatively inconvenient.
There is a problem. If the data is in the outer layer and the linked list is in the lower layer, how can we find the data from the linked list?
Offsetof macro and container_of macro
In order to find the outer element from the inner element, we need to use these two system macros. It looks complicated at a glance, but it is not hard to understand.
/*** @ Brief: determines the current member variable and the macro offset in the struct */# ifndef offsetof # define offsetof (type, member) (size_t) & (type *) 0)-> member) # endif
/*** @ Brief find the struct pointer containing the member variable */# ifndef container_of # define container_of (ptr, type, member) ({const typeof (type *) 0)-> member) * _ mptr = (ptr); (type *) (char *) _ mptr-offsetof (type, member) ;}) # endif
These two macros are more complex. The first is the offsetof macro, which uses the pointer 0 to find member variables. Let's think about how it is a common struct, how does the C compiler find a member?
For example:
/*** @ Brief data storage structure */typedef struct _ Int_List {list_node node; int data;} Int_List;
Suppose we useInt_List A
Statement, instantiate A struct, and obtain the address 0x00001000 of.
So is the start address of node 0x00001000?
Is the starting data address 0x00001000 + data offset?
So how can I calculate the data offset, not the following code:
(&A)->data - (&A);
If the address of A is 0, there is no need to reduce it, which is the usage in our macro definition.
The container_of macro adopts a similar idea. Since the offset of the current list_node member is found, the offset is the starting address of the struct surrounded by the outer layer.
Well, we can implement this linked list, but we don't have to worry about it. There is also a simple way to make our list_node member structure included, in the first position of our data storage structureIts address is the address that surrounds its structure.Directly convert the data type.
This idea is actually used to implement the Inheritance Mechanism of C language.
Github Project
At this point, we have explained how to implement the universal linked list. You can try to implement a unique universal linked list by yourself. The specific content will not be repeated here, I have released the complete project to Github. Welcome to fork for testing.