Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

A case study of Linux kernel macro Container _ Of

2025-04-06 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article introduces the Linux kernel macro Container _ Of case study, the content is very detailed, interested friends can refer to, hope to be helpful to you.

1. Int main () {Student stu; stu.id = 123456; strcpy (stu.name, "feizhufeifei"); stu.math = 90; stu.PE = 80; printf ("Student:%p\ r\ n", & stu); printf ("stu.ID:%p\ r\ n", & stu.ID); printf ("stu.name:%p\ r\ n", & stu.name) Printf ("stu.math:%p\ r\ n", & stu.math); return 0;}

The print result is as follows:

/ / address of the structure Student:0xffffcbb0 / / address of the first member of the structure stu.ID:0xffffcbb0 / / offset address + 0 stu.name:0xffffcbb4// offset address + 4 stu.math:0xffffcbd4// offset address + 24

?? We can see that the address of the structure is the same as the address of the first member of the structure. That's why we were refusing to build wheels! How to port and use the generic linked list of the Linux kernel (with complete code implementation) mentioned why struct list_head should be put in the first place in the structure.

If you don't quite understand, let's take a look at these two examples:

Struct A {int a; char b; int c; char d;}; an offset is 0, b offset is 4, c offset is 8 (the smallest integer multiple of 4 greater than 4 + 1), and d offset is 12. An alignment is 4 and size is 16.

Struct B {int a; char b; char c; long d;}; an offset is 0, b offset is 4, c offset is 5, d offset is 8. B alignment is 8 and size is 16.

We can see that the member variables in the structure actually store the offset address in memory. That is, the address of structure A + the offset address of the member variable = the starting address of the structure member variable.

Therefore, we can also deduce the address of structure An according to the starting address of the structure variable and the offset address of the member variable.

2. Container_ of Macro # define offsetof (TYPE, MEMBER) ((size_t) & (TYPE*) 0)-> MEMBER) # define container_of (ptr, type, member) ({\ const typeof ((type *) 0)-> member) * _ mptr = (ptr);\ (type *) ((char *) _ mptr-offsetof (type, member);})

?? First, look at the three parameters. Ptr is the pointer to the member variable, type is the type of structure, and member is the name of the member variable.

The function of the container_ of macro is to find the address of a member variable in the structure body by the address and name of that variable, as well as the structure type. What is used here is a technique that makes use of the compiler technique, that is, first to find the offset of the structure member in the structure, and then to get the address of the main structure variable according to the address of the member variable. The following is a specific analysis of each part.

3. Typeof

First, take a look at typeof, which is used to return the type of a variable, which is an extension of the GCC compiler, that is, typeof is compiler-related. It is neither required by the C language specification nor part of a standard.

Int main () {int a = 5; / / A variable of the same type as an is defined here, b typeof (a) b = 6; printf ("% d return% d\ r\ n", member b); / 5 6 return 0;} 4. (type *) 0)-> member)

((TYPE *) 0) convert 0 to a structure pointer of type type, in other words, let the compiler think that the structure starts at 0 at the beginning of the program segment, and if it starts at 0 address, the address of the member variable we get is directly equal to the offset address of the member variable.

(type *) 0)-> member) references the MEMBER member in the structure.

Typedef struct student {int id; char name [30]; int math;} Student; int main () {/ / forcibly converts the structure to a 0 address here, and then prints the address of the name. Printf ("% d\ r\ n", & (Student *) 0)-> name); / / 4 return 0;} 5. Const typeof (type *) 0)-> member) * _ mptr = (ptr)

This code means that you use typeof () to get the type of the member member attribute in the structure, then define a temporary pointer variable _ _ mptr of that type, and assign the address of the member pointed to by ptr to _ _ mptr

Why not just use ptr instead of doing it? I think it may be to avoid damaging the content pointed to by ptr and prt.

6. Offsetof (type, member))

((size_t) & ((TYPE*) 0)-> MEMBER)

Size_t is defined in the standard C library and is generally defined in 32-bit architectures as:

Typedef unsigned int size_t

In 64-bit architecture, it is defined as:

Typedef unsigned long size_t

As you can see from the definition, size_t is a non-negative number, so size_t is usually used to count (because counting does not need a negative area):

For (size_t ionomer) combined with the previous explanation, we can know that this sentence means to find an offset value of MEMBER relative to the zero address.

7. (type *) ((char *) _ mptr-offsetof (type, member))

This sentence means to convert _ _ mptr to char* type. Because the offset obtained by offsetof is in bytes. Subtract the two to get the starting position of the structure, and then cast to the type type.

8. For example, # define offsetof (TYPE, MEMBER) ((size_t) & (TYPE *) 0)-> MEMBER) # define container_of (ptr, type,member) ({\ const typeof (type *) 0)-> member) * _ mptr = (ptr);\ (type *) ((char *) _ mptr-offsetof (type,member));}) typedef struct student {int id; char name [30]; int math } Student; int main () {Student stu; Student * sptr= NULL; stu.id = 123456; strcpy (stu.name, "zhongyi"); stu.math = 90; sptr= container_of (& stu.id,Student,id); printf ("sptr=%p\ n", sptr); sptr= container_of (& stu.name,Student,name); printf ("sptr=%p\ n", sptr) Sptr= container_of (& stu.math,Student,id); printf ("sptr=%p\ n", sptr); return 0;}

The running results are as follows:

Sptr=0xffffcb90 sptr=0xffffcb90 sptr=0xffffcbb4

If you expand the macro, you may see it more clearly.

Int main () {Student stu; Student * sptr = NULL; stu.id = 123456; strcpy (stu.name, "zhongyi"); stu.math = 90; / / expand and replace sptr = ({const unsigned char * _ mptr = (& stu.id); (Student *) ((char *) _ mptr-(size_t) & (Student *) 0)-> id);}) Printf ("sptr=%p\ n", sptr); / / expand and replace sptr= ({const unsigned char * _ mptr = (& stu.name); (Student *) ((char *) _ mptr-((size_t) & (Student *) 0)-> name);}); printf ("sptr=%p\ n", sptr) / / expand and replace sptr= ({const unsigned int * _ mptr = (& stu.math); (Student *) ((char *) _ mptr-((size_t) & ((Student *) 0)-> math));}); printf ("sptr=%p\ n", sptr); return 0 } this is the end of the case study on the Linux kernel macro Container _ Of. I hope the above content can be of some help and learn more knowledge. If you think the article is good, you can share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report