您如何阅读此宏的第二行?在这种情况下,(类型*)0是什么意思?
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
Run Code Online (Sandbox Code Playgroud)
一个更易读的版本:
#define container_of(ptr, type, member) ( \
{ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) ); \
} \
)
Run Code Online (Sandbox Code Playgroud)
简而言之,宏定义了一个可用的“测试”,可以插入到 if 和其他语句中。((type *) 0) 将 NULL 引用转换为相关类型,然后获取该类型的“成员”子组件。typeof() 宏将返回与成员子“对象”关联的类型。因此它创建了一个与 type.member 子组件类型相同的常量 __mptr 变量。例如,如果我们有:
typedef struct foo_s {
int bogus;
int bar;
} foo;
Run Code Online (Sandbox Code Playgroud)
那么如果像这样调用:
foo blah; /* and initialize it of course */
int *myptr = &foo.bar;
foo *result = container_of(myptr, foo, bar);
Run Code Online (Sandbox Code Playgroud)
那么宏的第一行将变成以下内容:
const int *__mptr = (myptr);
Run Code Online (Sandbox Code Playgroud)
然后,宏的第二行计算原始结构的内存位置并返回该结构的内存指针,并将其正确地转换为该结构,并且展开后如下所示:
(foo *)( (char *)__mptr - offsetof(foo, bar));
Run Code Online (Sandbox Code Playgroud)
结果是这样的:
foo *result = container_of(myptr, foo, bar);
Run Code Online (Sandbox Code Playgroud)
允许您获取结构中的 myptr 元素并从中提取指向原始容器的指针。
现在,这在上面的示例中没有用,因为您已经可以访问包含的结构。但假装你没有,因为你所在的 API 没有通过它。当您通常无法获得父容器时,此宏是一种获取父容器的棘手方法。
当然,更好的做法是构建一个更好的 API,而无需这种 hack。但如果你c的话它很有用
您正在寻找的类型((type *)0)->member
。它实际上并没有取消引用指针(我告诉你,那将是疯狂的。疯狂!)
这是 C 的一个奇怪之处。如果他们写的话也许会更有意义,typeof(type.member)
但遗憾的是这是不允许的。