Q: How can I get the pointer of the structure through a variable in the structure ???
For details about container_of, see in kernel. h:
/**
* Container_of-cast a member of a structure out to the containing structure
* @ Ptr: the pointer to the member.
* @ Type: the type of the container struct this is embedded in.
* @ Member: the name of the member within the struct.
*
*/
# Define container_of (ptr, type, member )({/
Const typeof (type *) 0)-> member) * _ mptr = (ptr );/
(Type *) (char *) _ mptr-offsetof (type, member ));})
Container_of is widely used in Linux Kernel. It is used to obtain the entry address of a Member in a structure.
For more information about offsetof, see stddef. h:
# Define offsetof (TYPE, MEMBER) (size_t) & (TYPE *) 0)-> MEMBER)
TYPE is the TYPE of a struct. 0 is a hypothetical TYPE struct. MEMBER is a MEMBER of the struct. because the base address of the struct is 0, the MEMBER address is the offset of the MEMBER relative to the struct header address.
For typeof, this is an extension reserved word for gcc C language, used to declare the variable type.
Const typeof (type *) 0-> member) * _ mptr = (ptr); declares a pointer constant * _ mptr of the same type as member, and initialized to ptr.
(Type *) (char *) _ mptr-offsetof (type, member); it means the address of _ mptr minus the offset of member in this struct, then convert it to type pointer. this pointer is the entry address of member.
Example 1;
The container_of macro is defined in [include/linux/kernel. h:
# Define container_of (ptr, type, member )/
Const typeof (type *) 0)-> member) * _ mptr = (ptr );/
(Type *) (char *) _ mptr-offsetof (type, member ));
The offsetof macro is defined in [include/linux/stddef. h:
# Define offsetof (type, member) (size_t) & (type *) 0)-> member)
The following describes how to use the test. c program.
# Include <stdio. h>
Struct student {
Char name [20];
Char sex;
} Stu = {"zhangsan", 'M '};
Main ()
{
Struct student * stu_ptr; // stores the returned value of container_of macro
Int offset; // store the return value of the offsetof macro
// The following three lines of code are equivalent to the situation brought in by the container_of (& stu. sex, struct student, sex) parameter.
Const typeof (struct student *) 0)-> sex) * _ mptr = & stu. sex;
// First define a _ mptr pointer. The type is the sex member type in the struct student struct.
// Typeof is the type of get (struct student *) 0)-> sex), where this type is char
// (Struct student *) 0) explain at offsetof
Offset = (int) (& (struct student *) 0)-> sex );
/* (Struct student *) 0) to forcibly convert the 0 address to a pointer pointing to the student struct type
The 21 bytes starting from address 0 are used to store name and sex (char name [20] and char sex total 21 bytes)
Sex is stored in 20th bytes (starting from 0 bytes)
& (Struct student *) 0)-> sex retrieves the sex Address (20 here) and forcibly converts it to an integer
So offset is 20, and the result of printf will prove this */
Stu_ptr = (struct student *) (char *) _ mptr-offset );
/* (Char *) _ mptr-offset) Here first converts the _ mptr pointer to a character-shaped pointer
(Why? If _ mptr is an integer pointer _ mptr-offset, it is equivalent to subtracting sizeof (int) * offset bytes)
The offset value is equivalent to the first address of the struct where _ mptr is located (that is, the address of stu)
Then, we can forcibly convert the address to the struct student type */
Printf ("offsetof stu. sex = % d/n", offset );
Printf ("stu_ptr-> name: % s/tstu_ptr-> sex: % c/n", stu_ptr-> name, stu_ptr-> sex );
Return 0;
}
Example 2:
Its role is obvious, that is, the pointer to the entire struct variable is obtained based on the pointer of a domain member variable in a struct variable. For example, a struct variable is defined as follows:
1. struct demo_struct {
2. type1 member1;
3. type2 member2;
4. type3 member3;
5. type4 member4;
6 .};
7.
8. struct demo_struct demo;
At the same time, in another place, the pointer to a domain member variable in the variable demo is obtained, for example:
1. type3 * memp = get_member_pointer_from_somewhere ();
At this point, if you need to obtain a pointer to the entire struct variable, not just a pointer to its member variable in a certain domain, we can do this:
1. struct demo_struct * demop = container_of (memp, struct demo_struct, member3 );
First, we will expand container_of (memp, struct demo_struct, type3) according to the macro definition as follows:
1. struct demo_struct * demop = ({/
2. const typeof (struct demo_struct *) 0)-> member3) * _ mptr = (memp );/
3. (struct demo_struct *) (char *) _ mptr-offsetof (struct demo_struct, member3 ));})
Typeof is an extension of gnu c to Standard C. It is used to obtain the type of a Variable Based on the variable. Therefore, the function of row 2nd in the above Code is to first use typeof to obtain the type of the struct domain variable member3 as type3, and then define a Temporary Variable _ mptr of the type3 pointer type, and assign the value of the memp pointer to the domain variable in the actual struct variable to the Temporary Variable _ mptr.
Suppose the position of the struct variable demo in the actual memory is shown in:
Demo
+ ------------- + 0xA000
| Member1 |
+ ------------- + 0xA004
| Member2 |
|
+ ------------- + 0xA010
| Member3 |
|
+ ------------- + 0xA018
| Member4 |
+ ------------- +
The value of _ mptr after the first line of the Code is 0xA010.
Next, let's look at the 3rd lines of the above Code. here we need to describe offsetof, which is defined in include/linux/stddef. h. Its definition is as follows:
1. 24 # define offsetof (TYPE, MEMBER) (size_t) & (TYPE *) 0)-> MEMBER)
Similarly, we expand the above offsetof call, that is:
1. (struct demo_struct *) (char *) _ mptr-(size_t) & (struct demo_struct *) 0)-> member3 ));
It can be seen that the implementation principle of offsetof is to take the offset address of the Domain Member in the struct to the address 0, that is, the offset of the domain member variable to the first address of the struct variable.
Therefore, the value returned by offsetof (struct demo_struct, member3) is the offset of member3 from the demo variable. According to the preceding variable address distribution chart, offsetof (struct demo_struct, member3) returns 0x10.
Therefore, the above analysis shows that, __mptr = 0xA010, offsetof (struct demo_struct, member3) = 0x10.
Therefore, (char *) _ mptr-(size_t) & (struct demo_struct *) 0)-> member3) = 0xA010-0x10 = 0xA000, that is, the first address of the Structure Variable demo (as shown in ).
Therefore, container_of provides a function to obtain the pointer to the entire struct Variable Based on the pointer of a domain member variable in a struct variable.
Author "programmer"