define CONTAINER_OF (PTR, type, member) ({\
Const typeof ((type *) 0)->member) *__mptr = (PTR); \
(Type *) ((char *) __mptr-offsetof (Type,member));}
The effect is this: if you get a pointer to a member of a large structure, you can get a pointer to the structure by using the macro.
Suppose there is such a structure:
Struct student{
Type1 A;
Type2 B;
Type3 C;
};
Here the type1,2,3 is our usual common int,char and so on. The reason for not writing a specific type is to avoid having to consider the problem of byte alignment in memory as well.
Now use this structure to declare an object: struct student demo;
So the distribution of the demo in memory should be like this:
————— –0x6000
A
—————-0x6008
B
————— –0x600a
C
—————-0x600e
The above memory address distribution is all I write, because I do not have specific type1.2.3 is what type.
So what are the three parameters of the CONTAINER_OF macro, respectively?
PTR: Pointers to members of the structure body, such as type2 * pointer=&b
Type: This structure, such as struct student
Member: Name of the struct members, such as B
Look at the macro to see what it looks like. define CONTAINER_OF (pointer, struct student, B) ({\
Const typeof (((struct student*) 0)->b) *__mptr = (pointer); \
(struct student*) ((char *) __mptr-offsetof (struct student,b));
The initial replacement is this, but there is also a macro offsetof (struct student,b), for the moment do not look first.
Const typeof (((struct student*) 0)->b) *__mptr = (pointer); The function of this code is to declare a pointer __mptr. The TypeOf function is to get the type of the variable, so the __mptr type is type2. Then the value of the pointer pointer is assigned to it, in fact, two pointers to the same memory, that is, pointing to 0x6008.
Expand Offsetof (struct student,b) below to see what it is. define OFFSETOF (Type, member) ((size_t) & ((type *) 0)->member)
After replacement: define OFFSETOF (struct student, B) ((size_t) & ((struct student*) 0)->b)
(struct student*) 0) means to force the starting address of the student structure to 0, then the address of B is the offset of the relative 0 address, and then the location is 0x0008. in the above image;
Look Back (char __mptr: The pointer is forced to convert to (char), which is now a byte pointer. Why do you do that? Because the most basic units of memory storage are bytes. This conversion can be used to add and subtract is very convenient. &NBSP
To sum up, 0x6008-0x0008=0x6000. This address is the starting address of the demo structure and then converted to a pointer to the struct student type. #define OFFSETOF (Type, member) ((size_t) & ((type *) 0)->member)
First analyze how this macro works:
Altogether 4 steps
1. ((TYPE *) 0) converts 0 to a type pointer;
2. ((type *) 0)->member The data member in the Access structure;
3. & ((Type *) 0)->member) to remove the address of the data member; This implementation is equivalent to getting member members relative to their structure The offset of the body, which is where it is located in the corresponding structural body.
4. (size_t) (& (((type*) 0)->member) results conversion type. The ingenious thing is to convert 0 to (type*), the structure takes the first address of memory space 0 as the starting address, then the member address is naturally offset;
& Action cancels an action, rather than an identifier, if it is an expression.
&*a, for example, will directly seek out the address of a and will not access *a.
&a->member will cancel the operation of the access A->member and will only compute the A->member address