#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
第二行的作用是什么,去掉会可能引起什么样的后果?
“-”操作会影响减数获被减数的值吗?
“-”操作会影响减数获被减数的值吗?
--------------------------------------
不影响
第二行的作用是什么,去掉会可能引起什么样的后果?
--------------------
container_of 是一个精妙 的设计,网上已经有很多分析文章
({语句组}) 是GCC的扩展,返回语句组里最后一个语句的值。
这里也是返回相减后的值
确实可以简化成1行搞定,申请__mptr这个临时变量意义不大。原因我也不知,
大概 (__mptr - 偏移) 比 (ptr - 偏移) 更容易让人理解吧
每次看到container_of这个宏,都会对它的第一句话const typeof( ((type *)0)->member ) *__mptr = (ptr);产生疑问,今天终于下狠心解决了一下,去网上查了很多的资料,发现解释的都很牵强,不完全,大概分为两种类型,再此做下介绍:
1.检查ptr的类型是否为member类型(这个说的不明不白,但是我倾向于这种,下面会有解释)
2.第二个如下:(复制来的)
比如
#define min(x,y) ((x) < (y) ? (x) : (y))
当调用时用的是min(a++,b++)的时候,a和b的值就不对了(可能加了两次)。
而
#define min_t(type,x,y) \
({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
就没有这个问题。
复制完毕,这个比较有教育意义了,我也学习了,但是跟container_of这个宏还是不怎么沾边,毕竟ptr只用了一次,用来解释这个问题就牵强了
以下是我的理解:现在解释第一种类型,给人的第一个想法是ptr这个参数是错误的,不符合type->member,但是不会对结果产生任何影响,也不影响,(type *)((char *)__mptr - offsetof(type, member)); 这句话的运行,所以认为这句话是无用的。
大家主要把注意力放在了ptr这个参数上了,实际上 const typeof( ((type *)0)->member ) *__mptr = (ptr); 这句话把三个参数都检查了,试想如果member是type结构体里的成员,但是member不是ptr所指的类型,换句话说ptr是正确的但是member是错误的,(type *)((char *)__mptr - offsetof(type, member)); 显然结果是错误的。但是这句话编译器检查不出来,编译器不报错发出任何警告和错误,警告也是一种提示方式,因为c语言只能静态检查类型,所以只能通过编译器获取‘数据类型’的错误。虽然是警告,但是内核正常情况下发出任何警告。
还有一个原因是表明const typeof( ((type *)0)->member ) *__mptr = (ptr); 这句话确实是检查参数用的,试想如果内核开发者真的想赋值保存ptr他会怎么做?
应该会const typeof( ((type *)0)->member ) *__mptr = (((type *)0)->member)(ptr); 会强制类型转换一下防止参数传的类型不符而产生的警告,还是那句话,内核正常应用不会产生警告,它会扼杀一切不规范的苗头,这点可以从下一句的offsetof(type,member)的实现中可以看出
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
这个宏返回的是size_t类型,为什么呢?直接返回地址类型也对啊,不会影响结果的运行,但是这样使用是不规范的,会产生警告,内核是不允许的。
这个警告也许算内核开发人员的善意的提示吧。
最后声明一点,肯定会有人说,警告而已,真正做项目的时候谁看警告啊,你说的是对的,换个角度想,也算是我煽情臭屁一下,开发内核的人不是你们公司那种档次的人,如果他们拿出满天警告乱飞的操作系统,会让微软那波人鄙视地- -!!那样的操作系统你敢用?