为什么我们使用container_of
宏?
container_of(pointer, container_type, container_field);
据LDD说
“这个宏在一个类型为
container_field
的结构中接受一个名为container_field
的字段的指针,并返回一个指向包含结构的指针”。
我的问题是:
让我给你举个例子:
struct A { int some_data; int other_data; };
现在让我们说有这个function:
int get_some_data_from_other(int *other) { struct A *a = container_of(other, struct A, other_data); return a->some_data; }
正如您所看到的,我们能够通过知道指针所指向的结构的哪个字段来告诉包含给定int *other
的原始struct A
这里的关键是我们没有对结构本身的引用,而只是指向其成员之一的指针 。
这看起来很荒谬,但实际上在一些非常聪明的结构中很有用。 一个非常常见的例子是内核创建链表的方式。 我建议你在kernelnewbies.org上阅读这篇文章 。 让我们看一个简短的例子:
struct whatever { /* whatever data */ struct list_head mylist; };
所以struct whatever
具有一些数据的东西,但它也希望充当链表中的节点。 他们在学校教你的是拥有一个不同的结构,包含next
/ prev
指针以及指向struct whatever
(或void *
)的指针。 这样,您就拥有了通过其获取数据的节点。
按照所有软件工程标准,这实际上是一件好事。 但软件工程标准对效率的要求很低。 请参阅为什么我应该用C编写ZeroMQ,而不是C ++(第二部分) 。
底线是,使用传统方法,您必须与数据节点分开分配链接列表节点,即您将内存分配,解除分配,碎片和缓存未命中等的开销加倍。 Linux内核的方式恰恰相反。 每个数据节点都包含一个通用链表节点。 通用链表节点不知道有关数据或它们如何分配的任何信息,只知道如何连接到其他链表节点。
让我们深入了解一下:
+-------------------+ +---------------------+ +---------------------+ | | | | | | | WHATEVER DATA | | WHATEVER DATA 2 | | WHATEVER DATA 3 | | | | | | | | | | | | | | | | | | | | | | | | | +-------------------+ +---------------------+ +---------------------+ | |----->| |----->| | | mylist | | mylist 2 | | mylist 3 | | |<-----| |<-----| | +-------------------+ +---------------------+ +---------------------+
你所拥有的链表是struct list_head
中指向其他struct list_head
的指针。 请注意,它们并不指向struct whatever
,而是指向那些结构中的mylist
。
假设你有一个节点, struct whatever w
。 您想要找到下一个节点。 你能做什么? 首先,您可以执行w.mylist.next
以获取指向下一个节点的mylist
的指针。 现在,您必须能够提取包含该节点的实际struct whatever
。 这就是使用container_of
的地方:
struct whatever w_next = container_of(w.mylist.next, struct whatever, mylist);
最后,请注意Linux内核具有遍历链表的所有节点的宏,这通常不是您想要的,因此您实际上不需要自己直接使用container_of
。
Why do we use container_of macro ?
容器的宏用于获取指向包含元素的结构的开头的指针。
例如
struct container { int some_other_data; int this_data; }
并且指针int *my_ptr
指向this_data
成员,您将使用宏来获取指向struct container *my_container
的指针:
struct container *my_container; my_container = container_of(my_ptr, struct container, this_data);
将this_data
的偏移量考虑到结构的开头对于获取正确的指针位置至关重要。
实际上,您只需从指针my_ptr
减去成员this_data
的偏移量即可获得正确的位置。
另见这里清楚你的疑惑。
是的,您可以使用自己编写的演员/作业,但它有一些优点。
效率 – 使用宏而不是声明整个演员表并不容易吗?
维护 – 如果每个人都使用宏,只需编辑宏,就可以在整个项目中轻松更改指针分配的方式。
可读性 – 什么是易读的? 一个明确的演员或宏为你做的?
安全性 – 您可能相信此宏可以工作,并且它运行任何重要的强制转换和类型检查,比您自己的代码更好。
以上就是c/c++开发分享怀疑linux中的container_of宏相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/518774.html