【发布时间】:2016-02-04 23:36:43
【问题描述】:
宏定义为
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
我查看了此处的一些其他问题以及互联网上的其他一些资源,我很确定我了解此宏的工作原理。
我认为它的作用: 在第一行中,它创建了一个新指针,其类型为指向成员类型的指针,并将给定指针的值分配给该指针。然后在第二行中,它使用 offsetof 来查找结构或联合的开头地址。
我的问题是为什么这条线 const typeof( ((type *)0)->member ) *__mptr = (ptr); 在这里。似乎设置了正确的指针类型,然后在下一行立即转换为char *。
所以我的问题是为什么__mptr 必须转换为不同类型的指针?为什么不能将其保留为我刚刚将其设置为的任何类型,然后从该指针中减去偏移量,因为无论如何我在减法之后再次对其进行转换。此外,虽然我(认为)我理解第一行在做什么,但我不明白为什么它甚至是必要的。
为什么这样做比这样好:
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)(__mptr - offsetof(type,member) );})
或者这个
#define container_of(ptr, type, member) ({ \
(type *)( (char *)ptr - offsetof(type,member) );})
【问题讨论】:
-
如果你不强制转换为
char*,那么指针算法对于任何大小不是sizeof(char)的类型都会产生不同的结果。 -
@paddy:严格来说,即使大小相同,使用不同的类型也会违反严格的别名规则,因此会调用 UB。
-
@Olaf,哈哈,但这就像超速,对吧?从技术上讲是违法的,但如果你真的以公布的速度行驶,那就太奇怪了。
-
@paddy 所以我们将它转换为 char* 因为 char 的大小为 1 字节?因为不是每个指针都有大小?
-
这与指针的大小无关。它大约是它指向的类型的大小。阅读 C 中指针算法的工作原理。此外,@Olaf 对严格别名有一个很好的观点。但是,如果您对指针算法感到困惑,那么也许在处理严格别名之前了解一下。
标签: c pointers casting linux-kernel macros