#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
我已经知道第一行是用于类型检查,但对于第二行,是
为什么要进行(char *)
投射?我找不到解释这一点
我自己做了一些实验代码,即使没有演员,结果似乎也很好。
答案 0 :(得分:6)
获取计算的字节级地址。否则,指针算法将根据所指向的类型进行调整,这会因offsetof
计算以字节为单位的偏移量而中断。
在这样的低级基元内部,转换为char *
非常常见,因为有时你真的需要将内存视为“字节数组”并在该级别操作它。
以此结构为例:
struct demo {
int foo;
float bar;
};
现在,如果我们这样做了:
struct demo test;
float *intptr = &test.bar;
我们应该能够使用test
container_of()
的指针
struct demo *owner = container_of(intptr, struct demo, bar);
这将扩展为:
struct demo *owner = {(
const typeof( ((struct demo*)0)->bar) *__mptr = (intptr);
(struct demo*)( (char *)__mptr - offsetof(struct demo,bar) );})
所以第一行声明了float
指针__mptr
并将参数值复制到它。
第二行将成员指针强制转换为char *
,然后在bar
内减去struct demo
的偏移量(如果sizeof (int)
为4,则为4;) “备份”到整个结构test
的地址。
如果转化为char *
,那么4
就会被float
解释(因为__mptr
是float *
)这显然会备份得太远(16个字节而不是4个,假设float
也是4个字节)导致可怕的破损。
请注意,包含{(
扩展的container_of()
语法是GCC扩展名;这在标准C中不起作用。
有关container_of()
的更多信息,请参阅this page。