这个宏定义的含义是什么?

6
你如何读取此宏的第二行?在这个上下文中,(type *)0是什么意思?
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

2
请注意,这里使用了两个gcc扩展:({ })用于在表达式中评估具有局部变量的块,以及typeof用于声明与成员类型相同的变量。 - Jens Gustedt
5个回答

5
你正在查找((type *)0)->member类型。它实际上并没有解引用指针(那会是疯狂的,我告诉你,疯狂!)。
这是C语言的一种奇怪现象。也许如果他们写成typeof(type.member)会更有意义,但遗憾的是这是不允许的。

这不是“C语言的怪异之处”,而是GCC的怪异之处。typeof是一个非标准扩展(例如GCC)。 - undur_gongor
很有趣,我从来不知道。虽然,我猜gcc是罪魁祸首也不意外。 - Robert Martin
我理解在这里使用0/NULL是有意义的,但为什么不使用typeof(((type *)123)->member)呢? 0和任何值一样好吗?或者可能有更多的东西,比如强制类型转换除了0以外都是未定义的? 我知道这对于offsetof是必须的,但它与typeof的用法不同。 - dashesy

4
一个更易读的版本:
#define container_of(ptr, type, member) (                  \
   {                                                       \
      const typeof( ((type *)0)->member ) *__mptr = (ptr); \
      (type *)( (char *)__mptr - offsetof(type,member) );  \
   }                                                       \
)

简而言之,该宏定义了一个可用于if和其他语句中的“test”。((type *) 0)将空引用转换为相关类型,然后获取该类型的'member'子组件。typeof()宏将返回与成员子“对象”关联的类型。因此,它创建了一个常量__mptr变量,其类型与type.member子组件相同。例如,如果我们有:
typedef struct foo_s {
   int bogus;
   int bar;
} foo;

如果按照以下方式调用:

foo blah;  /* and initialize it of course */
int *myptr = &foo.bar;

foo *result = container_of(myptr, foo, bar);

然后宏的第一行将变成以下内容:

const int *__mptr = (myptr);

宏的第二行计算原始结构体的内存位置,并返回该结构体的内存指针,并适当地将其转换为该结构体,展开后如下所示:
(foo *)( (char *)__mptr - offsetof(foo, bar));

结果如下所示:
foo *result = container_of(myptr, foo, bar);

允许您获取结构体中的myptr元素,并从其中提取指向原始容器的指针。

现在,在上面的示例中,这并不实用,因为您已经可以访问包含的结构体。但是假设您没有访问权限,因为您正在使用的 API 没有传递它。这个宏是一个巧妙的方法,可以在通常不可用时获取父容器。

当然,更好的做法是构建一个更好的 API,不需要此 hack。但是如果必要,它非常有用。


Wes,这个解释真的帮助我理解了正在发生的事情。谢谢!! - lordhog

1

(type *)0 实际上就是 NULL。 第二行代码获取了您提供值的地址,并将其减去在结构体中的位置。这样就能得到结构体的地址。


1

这就像是 offsetof(type, member) 的定义一样。

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

(TYPE *)0 将 0 强制转换为指向类型 TYPE 的指针,而 ((TYPE *)0)->member 指向 TYPE 的成员。


编译器实现可以像这样定义 offsetof,但通常不会这样做,而是使用其他一些内部技巧。 - Jens Gustedt

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接