4.2 container_of的书写
在对内核的理解上没有所谓的捷径,该花多少时间,该花多少精力,它就是应当要花到相当的程度才能产生理解。而且不应放过每一个细节,因为不能理解往往是一些细节没有做到极致。
近来我发觉到linux内核对container_of有两种不同的写法,有一种版本是这样写的:
#define container_of(ptr, type, member) ({ \ const typeof( ((type *)0)->member ) *__mptr = (ptr); \ (type *)( (char *)__mptr - offsetof(type,member) );})
而另一种是这样写的:
#define container_of(ptr, type, member) ({ \ void *__mptr = (void *)(ptr); \ static_assert(__same_type(*(ptr), ((type *)0)->member) || \ __same_type(*(ptr), void), \ "pointer type mismatch in container_of()"); \ ((type *)(__mptr - offsetof(type, member))); })
就实际效果而言,如果输入规范的话,两种书写算式事实上都能返回到被认为正确的结果。不过后一种还额外提供了一个检查参数输入是否得当的功能。
它是通过利用__same_type(type1,type2)结合static_assert(expr,msg)表达式,如果出现判断type1和type2类型不相同,则_same_type(type1,type2)等于0,这将导致static_assert(expr,msg)中的expr表示为0,那么在编译的阶段(还没到代码运行),编译器就会报出“Static error”并输出"msg"的信息。
在这里它要求ptr必须是member类型的指针,或者说ptr是一个空类型,否则就会校验出类型不匹配的错误信息:“pointer type mismatch in container_of()”
这给因使用container_of导致的错误提供了一个检测接口。