【问题标题】:Why is there a cast to (char *) before pointer arithmetic? (container_of() internals)为什么在指针算术之前要强制转换为 (char *)? (container_of() 内部)
【发布时间】: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


【解决方案1】:

因为减法会错误地将偏移量乘以 ptr 的大小。

也就是说,没有它,你会得到以下结果:

(type *)( (char *)__mptr - sizeof *__mptr * offsetof(type,member) );})

【讨论】:

  • 啊,好吧,为什么你不能只使用 ptr 并将其转换为 char* 呢?
  • 一个可以,所以很难说为什么__mptr被搅动了。它可能会在参数类型奇怪时消除警告,或者它可能与优化器和别名检测交互-基于上面讨论的优化。也许它解决了一个错误。
猜你喜欢
  • 1970-01-01
  • 2021-05-08
  • 2013-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-10
  • 2011-12-16
  • 2011-04-12
相关资源
最近更新 更多