#define list_entry(ptr, type, member) container_of(ptr, type, member)
when we are programming, we often look for the address of one of the members in the case where we know the address of the struct, but if we know the address of the member, if we find the corresponding address of the struct? in the Linux kernel, the function that gets the address of the node is List_entry (), and its macro definition is as shown above.
let's look at the definition of container_of (PTR, type, member) and find that it remains a macro definition:
#define container_of(ptr, type, member) \
({ \
const typeof(((type *)0)->member) * __mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); \
})
Incontainer_of (PTR, type, member) in the macro definition, the true return node address is the last word,and in the last word,offsetof (TYPE, MEMBER) is still a macro definition.
#define ( type MEMBER ) size_t Span class= "pun") & (( type *) 0 member )
typedef __kernel_size_tsize_t;
typedef unsigned int__kernel_size_t;
By looking through the layers we'll talk about the concrete implementation of the List_entry () function, and we'll start with the bottom up.
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
This is our custom struct type, with at least one List_head member variable inside it, as follows:
- < Code class= "Language-cpp" >struct TYPR
{
//...
struct List_head member
Span class= "com" >//...
};
Where List_head is also a struct, the definition of which we'll talk about later.
This is the variable name of the type List_head variable in the type object.
(TYPE *) 0: Cast 0 To type pointer, the pointer must point to the 0 address (the data segment base). & ((TYPE *) 0)->member This sentence is actually& (((TYPE *) 0)->member),using this pointer to access the type'smember members and get their addresses. Since the starting address of this pointer is 0, then& ((TYPE *) 0)->member is the starting address of a type variablewith the variable internalmember The offset between the starting address of the member variable, which is true for all type variables. So, the next idea is clear, we just need to know a type variablemember The starting address of the variable, minusOffsetof (Type, MEMBER) This offset, you can get the start address of the type variable.
The correspondence of it is as follows:
The idea is clear, but there are some details that need attention, and we continue to look at the code.
2.
#define container_of(ptr, type, member) \
({ \
Span class= "KWD" >const typeof (( type *) 0 member ) * __mptr = ( ptr \
(type *)((char *)__mptr - offsetof(type, member)); \
})
- Const typeof (((type *) 0)->member) * __mptr = (PTR);
Since we're going to force type conversions on pointers, here we apply a pointer to the same position as PTR. The PTR here refers to the actual address of the List_head member.
Since the Offsetof () function evaluates the number of offset bytes, here(char *) __MPTR allows the pointer to add and subtract operation step 1ByteThe starting address of the type variable can then be subtracted and finally passed(Type *) type conversion, which translates the address to a pointer of type. and then up is some macro definition there's nothing to say.
From for notes (Wiz)
Detailed explanation of structure address--list_entry () by struct member address calculation