什么时候使用container_of宏?
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这是一种回避 C 没有泛型或模板这一事实的方法。
你想要一个通用的链表,所以你只需将指针放在节点本身内部(这样你就可以抽象出结构本身的管理),然后使用
CONTAINING_RECORD
在中查找其余数据你自己的代码,例如:现在,给定一个
struct Node
,你可以通过以下方式找到它的Item
: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.:Now, given a
struct Node
, you can find itsItem
by saying: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 callcontainer_of
to find its parent structure.对于未来的搜索:这是迄今为止我发现的最好的解释:
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 指针。我们可以省略第一行,宏可以是
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 asptr
. Then it gets the offset of thatmember
within thestruct
, and subtracts it from the actual address of the member of thestruct ‘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 thatoffsetof
‘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
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 calledmember
(however this is done byoffsetof
macro too, I think), and ifptr
isn’t a pointer to the correct type (the type of themember
), the compiler will print a warning, which can be useful for debuging."它将指向结构成员的指针调整为指向包含结构的指针;这在内核中以多种方式使用,最常见的可以被描述为具有静态偏移量的向下转型,其中外部结构是从内部派生(通过包含)的,并且调用者调用内部对象上的方法,该方法是然后分派到外部对象上的方法。
好吧,没有编译器的 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.