Let's start with a simple version.
1 /* given a pointer @ptr to the field @member embedded into type (usually2*/3
#define
4 ((Type *) ((
char *) (PTR)-(
Char *) (& ((type *)
0)- >member)))
Function: Mainly used for the structure, given a pointer ptr to a struct type instance of the member member, returns the first address of this struct instance, that is, the struct instance of the pointer, verbose a heap, not as an example:
1typedefstructabc{2 CharA;3 Charb;4 intC;5 }abc;6 7 intMainintargcConst Char*argv[])8 {9 ABC ins;Ten Oneprintf"%p\n", Container_of (&ins.c, ABC, c)); Aprintf"%p\n", &ins); - return 0; -}
The printed value should be equal to the first address of the struct ins. We will expand the macro:
Container_of (&ins.c, ABC, c); // after expansion ((ABC *) ((char *) (&INS.C)-(Char *) (& ((ABC *)0)->c)));
The 2 sides of the minus sign are 2 sections, the front: (char *) (&INS.C), which is the pointer to the member C of INS, followed by: (char *) (& (((ABC *) 0)->c) is the offset of member C relative to the structure's ABC pointer, For example, in this example:
The pointer to member C (&INS.C) minus the offset of member C (offset) then gets the struct INS first address. If I only know the pointer value of a struct member, then you can get the struct pointer by container_of macro, then you can access any member of it.
Upgrade version:
1 #define Offsetof (TYP,MEMB) ((long) (long_ptr_t) ((char *) & ((((Typ *) 0)->memb))2#define container_of (PTR, type, member) ({ 3 consttypeof((type *)0) Member) *__mptr = (PTR); 4 (Type *) ((char *) __mptr-offsetof (Type,member));})
What is the improvement of the upgraded version? I'm going to summarize what I know:
1.const modification to ensure that the incoming PTR pointer is not modified. 2. Use an intermediate variable, define a variable pointer __mptr for a member member type, and assign the PTR to it. Why would you do that? Just in case, if you make a mistake. The pointer is not pointing to the member member, the compiler will have at least one warning.
3.OFFSET macro uses (long) (long_ptr_t) 2 data types for strong turn I didn't read too much, (long long) 64 bits? Is it possible for a member to have an offset of more than 32 bits? It's __mptr. This address value may exceed 32 bits (addressing more than 4G). Puzzled.
Reference:
http://broken.build/2012/11/10/magical-container_of-macro/
Linux 3.13.0 kernel.
Linux Kernel Macro container_of