你什么时候使用container_of宏?

时间:2011-02-28 17:01:52

标签: c macros linux-kernel device-driver kernel

我知道宏的作用。

在许多内核级代码中,它通常用于遍历链表。

我想找到其他有用的案例 你什么时候使用container_of或CONTAINING_RECORD宏? 什么时候宏非常有用?

4 个答案:

答案 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相同的地址。然后它获取memberstruct的偏移量,并从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支持。