一个更易读的版本:
#define container_of(ptr, type, member) ( \
{ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) ); \
} \
)
简而言之,宏定义了一个可用的“测试”,可以插入到 if 和其他语句中。 ((type *) 0) 将 NULL 引用转换为相关类型,然后获取该类型的“成员”子组件。 typeof() 宏将返回与成员子“对象”关联的类型。所以它创建了一个与 type.member 子组件相同类型的常量 __mptr 变量。例如,如果我们有:
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 没有通过它。这个宏是获取父容器的一种棘手方法,而您通常不会使用它。
当然,更好的做法是在不需要这种 hack 的情况下构建更好的 API。但是如果你c它会很有用