什么时候使用container_of宏?

发布于 2024-10-20 03:53:04 字数 211 浏览 7 评论 0原文

我知道宏是做什么的。

在许多内核级代码中,经常使用它来遍历链表。

我想找到其他有用的案例。
什么时候使用container_of或CONTAINING_RECORD宏?
宏什么时候特别有用?

I know what the macro does.

In many kernel level codes, it is often used to traverse linked-list.

I want to find other useful cases.
When do you use container_of or CONTAINING_RECORD macro?
When is the macro extremely useful?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

她说她爱他 2024-10-27 03:53:04

这是一种回避 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;
}

现在,给定一个struct Node,你可以通过以下方式找到它的Item

CONTAINING_RECORD(ptr, Item, node)

It's a way to go around the fact that C doesn't have generics or templates.

You want a generic linked list, so you just put the pointers inside the node itself (so that you can abstract away the management of the structure itself), then use CONTAINING_RECORD to find the rest of the data in your own code, e.g.:

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;
}

Now, given a struct Node, you can find its Item by saying:

CONTAINING_RECORD(ptr, Item, node)
遗失的美好 2024-10-27 03:53:04

container_of 允许您通过省略指向父结构的指针来简化数据结构。

它在链表实现中使用,以便列表节点可以是任何结构的元素,并且任何人都可以找到父结构而无需携带显式指针。

另一个例子是struct work_struct。工作队列工作函数接收 work_struct 作为参数,并且它曾经具有通用的“数据”有效负载。此数据值已删除,使结构更小,因为工作函数可以调用 container_of< /code> 查找其父结构。

container_of allows you to simplify your data structures by omitting pointers to parent structures.

It's used within the linked list implementation so that the list node can be an element of any structure, and anyone can find the parent structure without carrying around an explicit pointer.

Another example is struct work_struct. A workqueue work function receives a work_struct as an argument, and it used to have a generic "data" payload. This data value was removed, making the structure smaller, as the work function can call container_of to find its parent structure.

吲‖鸣 2024-10-27 03:53:04

对于未来的搜索:这是迄今为止我发现的最好的解释:

http://psomas.wordpress.com/2009/07/01/weird-kernel-macros-container_of/

基本上(引用):

“现在我们可以理解(至少部分)什么它声明了一个指向 ptr 指向的结构成员的指针,并将 ptr 分配给它,现在 __mptr 指向与 相同的地址。然后它获取该成员struct中的偏移量,并从struct'实例的成员的实际地址中减去它。 '(ie __mptr)(char *)__mptr 转换是必要的,这样“指针算术”就能按预期工作,即从 __mptr 中精确减去。 offsetof'返回'的(size_t)字节。”

另外,还有另外两个重要提示(引用):

“此时,我真的不明白为什么我们不能直接使用 ptr 指针。我们可以省略第一行,宏可以是

#define container_of(ptr, type, member) (type *)( (char *)(ptr) - offsetof(type,member) )

ptr 仅使用一次——我们不需要担心副作用。
也许这只是良好的编码实践。”

并且,原始帖子的后来编辑(引用):

“显然,第一行用于‘类型检查’。它确保 type 有一个名为 member 的成员(不过我认为这也是由 offsetof 宏完成的),并且如果 ptr 不是指向正确类型(成员 的类型)的指针,编译器将打印一条警告,这对于调试很有用。”

For the future searche(r)s: this is the best explanation that I found so far:

http://psomas.wordpress.com/2009/07/01/weird-kernel-macros-container_of/

Basically (quote):

"Now we can understand(at least partially) what the macro does. It declares a pointer to the member of the struct that ptr points to, and assigns ptr to it. Now __mptr points to the same address as ptr. Then it gets the offset of that member within the struct, and subtracts it from the actual address of the member of the struct ‘instance’(ie __mptr). The (char *)__mptr cast is necessary, so that ‘pointer arithmetic’ will work as intended, ie subtract from __mptr exactly the (size_t) bytes that offsetof ‘returns’."

and, also, two other significant hints (quote):

"At this point, I really can’t understand why we couldn’t use the ptr pointer directly. We could ommit the first line, and the macro could be

#define container_of(ptr, type, member) (type *)( (char *)(ptr) - offsetof(type,member) )

ptr is used only once — we don’t need to worry about side effects.
Maybe it’s just good coding practice."

and, the later edit of the original post (quoted):

"Apparently, the first line is there for ‘type checking’. It ensures that type has a member called member (however this is done by offsetof macro too, I think), and if ptr isn’t a pointer to the correct type (the type of the member), the compiler will print a warning, which can be useful for debuging."

情绪少女 2024-10-27 03:53:04

它将指向结构成员的指针调整为指向包含结构的指针;这在内核中以多种方式使用,最常见的可以被描述为具有静态偏移量的向下转型,其中外部结构是从内部派生(通过包含)的,并且调用者调用内部对象上的方法,该方法是然后分派到外部对象上的方法。

好吧,没有编译器的 OO 支持。

It adjusts a pointer to a member of a struct to a pointer to the containing struct; this is used in various ways in the kernel, the most common could be described as a downcast with a static offset where the outer structure is derived (by inclusion) from the inner, and the caller invokes a method on the inner object, which is then dispatched to a method on the outer object.

Well, that, without OO support from the compiler.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文