你如何阅读这个宏的第二行?在这种情况下(类型*)0意味着什么?
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
答案 0 :(得分:4)
您正在找到((type *)0)->member
的类型。它实际上并没有取消引用指针(我告诉你,这将是疯狂的。疯狂!)
这是C的一种奇怪。也许如果他们写typeof(type.member)
会更有意义,但遗憾的是这是不允许的。
答案 1 :(得分:3)
稍微可读的版本:
#define container_of(ptr, type, member) ( \
{ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) ); \
} \
)
简而言之,宏定义了一个可用的“测试”,可以插入到if和其他语句中。 ((type *)0)将NULL引用转换为相关类型,然后获取该类型的“member”子组件。 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没有通过它。当你通常没有它时,这个宏是获取父容器的一种棘手方法。
当然,更好的做法是构建一个更好的API,而不需要这种黑客攻击。但是,如果你是
,它会很有用答案 2 :(得分:1)
(type *)0
基本上是NULL
。
第二行获取您给出的值的地址,并在结构中减去其位置。它为您提供了结构的地址
答案 3 :(得分:1)
就像offsetof(type,member)的定义一样。
#define offsetof(TYPE,MEMBER)((size_t)&((TYPE *)0) - > MEMBER)
(TYPE *)0将0转换为指向类型为TYPE的0的指针,((TYPE *)0) - >成员指向TYPE的成员。
答案 4 :(得分:1)
实际上,第二行是多余的,仅用于类型检查。
#define container_of(ptr, type, member) ({\
(type *)( (char *)ptr - offsetof(type,member) );})
除了类型检查功能外,具有相同的语义。