答案 0 :(得分:7)
container_of
允许您通过省略指向父结构的指针来简化数据结构。
它在链表实现中使用,因此列表节点可以是任何结构的元素,任何人都可以找到父结构而不带有显式指针。
另一个例子是struct work_struct
。工作队列工作函数接收work_struct作为参数,并且它曾经具有通用的“数据”有效负载。此数据值为removed,使结构更小,因为工作函数可以调用container_of
来查找其父结构。
答案 1 :(得分:5)
这是一种绕过C没有泛型或模板这一事实的方法。
你想要一个通用的链表,所以你只需将指针放在节点本身内(这样就可以抽象出结构本身的管理),然后用CONTAINING_RECORD
找到其余的数据。你自己的代码,例如:
struct Node { struct Node *prev, *next; }
//Now you can define functions that operate on a generic struct Node*
struct Item
{
int myData;
struct Node* node; //this would point to the 'node' member of another Item
}
现在,给定struct Node
,您可以通过以下方式找到Item
:
CONTAINING_RECORD(ptr, Item, node)
答案 2 :(得分:4)
对于未来的搜索(r):这是我到目前为止找到的最佳解释:
http://psomas.wordpress.com/2009/07/01/weird-kernel-macros-container_of/
基本上(引用):
“现在我们可以理解(至少部分地)宏的作用。它声明了一个指向ptr
指向的结构成员的指针,并将ptr赋给它。现在__mptr
点与ptr
相同的地址。然后它获取member
中struct
的偏移量,并从struct ‘instance’(ie __mptr)
成员的实际地址中减去它。 (char *)__mptr
强制转换是必要的,因此“指针算术”将按预期工作,即从__mptr
中精确减去(size_t)
'返回'offsetof
个字节。“
以及其他两个重要提示(引用):
“此时,我真的无法理解为什么我们不能直接使用ptr指针。我们可以省略第一行,宏可以是
#define container_of(ptr, type, member) (type *)( (char *)(ptr) - offsetof(type,member) )
ptr
仅使用一次 - 我们不需要担心副作用。
也许这只是很好的编码实践。“
以及后期编辑的原始帖子(引用):
“显然,第一行是'类型检查'。它确保type
有一个名为member
的成员(但这也是由offsetof
宏完成的,我认为),如果ptr
不是指向正确类型(member
的类型)的指针,编译器将打印一个警告,这对于调试非常有用。“
答案 3 :(得分:0)
它将指向结构成员的指针调整为指向包含结构的指针;这在内核中以各种方式使用,最常见的可以描述为具有静态偏移的向下转换,其中外部结构从内部派生(通过包含),并且调用者在内部对象上调用方法,这是然后调度到外部对象上的方法。
那么,没有编译器的OO支持。