Http://blog.csdn.net/hgf1011/article/details/4635888
Containing_record in EFI
Almost all the efi bios is completed in C, and it uses almost all the skills of C language to the extreme. The essence of C is the pointer, and the macro is also very commendable. The comments of programmers on macros are mixed. Some people say that macros are the source of all evil, while others praise them as a blade. I personally think that macros are not omnipotent, but in some cases, using macros can greatly improve the readability of the program. Some cross-platform features cannot be used without macros. _ Cr is a macro often used in EFI. Let's take a look at its true nature:
//
// Containing_record-returns a pointer to the structure
// From one of it's elements.
//
# DEFINE _ Cr (record, type, field) (type *) (char8 *) (record)-(char8 *) & (type *) 0) -> Field )))
This macro is used to obtain the base address of a struct Based on the address of a struct member variable. Example:
Struct _ Test
{
Char8 t0;
Uint16 T1;
Uint8 T2;
Uint32 T3;
};
We get the T2 address t2ptr in a certain place. To obtain the base address of the struct where T2 is located, we can do this: struct _ test * bptr = _ Cr (t2ptr, struct _ test, T2); after the pre-processing is expanded, struct _ test * bptr = (struct _ test *) (char8 *) (t2ptr)-(char8 *) & (struct _ test *) 0)-> T2), in fact, I think the key part is in this sentence "(type *) 0)-> field ", in fact, it obtains the offset position (offset) of the member in the struct, and the base address is obtained after the address of the member variable minus its offset in the struct.
As shown in figure 1, if the T2 address is 0x1005, what is the bptr? Just use the offset of the t2-t2 (0x03), that is, 0x1002. Is it easy?
It is probably the same as what a hero sees. Macros in this form also exist in Linux kernel and Windows kernel, but their names are different. Let's take a look at what it looks like in Linux:
/**
* 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 ));})
# Define offsetof (type, member) (size_t) & (type *) 0)-> Member)
Let's take a look at its appearance in Windows Kernel J:
# Define containint_record (address, type, field )/
(Type *) (pchar) (Address)-(pchar) (& (type *) 0)-> Field )))
They all play the same role. Isn't it a bit of a big copy of the article...
Peter
2009-10-6