[Question ]:
Calculate the first address of a struct object based on the address of a member.
[Example ]:
Struct
{
Int x;
Int y;
Int z;
}
# Define GET_HEADER_ADDR (MEMBER) (you can implement it)
Void main ()
{
Struct A myTest;
Printf ("addr is % d", GET_HEADER_ADDR (myTest. z ));
}
Let's not look at the answer below. Let's try to implement the macro above.
[Answer and analysis process]
In the Linux kernel, two very clever macros are used for implementation. One is the offsetof macro and the other is the container_of macro. The two macros are described below.
1. offsetof macro
[Definition]: # define offsetof (TYPE, MEMBER) (size_t) & (TYPE *) 0)-> MEMBER)
[Function]: obtains the offset of a struct variable Member in this struct.
[Example ]:
Struct
{
Int x;
Int y;
Int z;
};
Void main ()
{
Printf ("the offset of z is % d", offsetof (struct A, z ));
}
// The output result is 8.
[Analysis ]:
The Macro, TYPE is the struct TYPE, and MEMBER is the variable name in the structure.
(TYPE *) 0) indicates that the spoofing compiler has a pointer to the structure TYPE, and its address value is 0.
(TYPE *) 0)-> MEMBER is the address for obtaining the MEMBER variable MEMBER in the struct TYPE. because the base address is 0, the MEMBER Address is of course the offset of MEMBER in TYPE.
2. container_of macro (that is, the function in the question is implemented)
[Definition ]:
# Define container_of (ptr, type, member) ({const typeof (type *) 0)-> member) * _ mptr = (ptr); (type *) (char *) _ mptr-offsetof (type, member ));})
[Function ]:
Obtain the first pointer of a struct (type) from a member variable (member) pointer (ptr.
[Example ]:
Struct
{
Int x;
Int y;
Int z;
};
Struct A myTest;
Int * pz = myTest. z;
Struct A * getHeaderPtr (int * pz)
{
Return container_of (pz, struct A, z );
}
[Analysis ]:
(1) typeof (type *) 0)-> member) is the variable type used to retrieve members of member.
(2) define _ mptr pointer ptr as the pointer to the member variable (that is, to the variable pointed to by ptr)
(3) (char *) _ mptr-offsetof (type, member) use the actual address of the member variable minus the offset of the variable in the struct to find the starting address of the struct.
(4) ({}) The extension returns the value of the last expression in the program block.
This article is from the "three shadows" blog