pru*_*nat 13 c linked-list standards-compliance c99 linux-kernel
在查看Linux内核的双链循环列表的实现时,我发现了以下宏:
#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)
这种方式的工作方式是返回指向结构的指针,只给出其成员之一的地址:
struct blabla
{
int value;
struct list_head *list;
}
Run Code Online (Sandbox Code Playgroud)
因此,只有指向list的指针,你才可以获得指向blabla的指针(并获得"value").对于我的问题,我如何使其尽可能便携(符合C89/C99的最佳情况?).由于使用了typeof(),这只是gcc.
这是我到目前为止所得到的:
#define container_of(ptr, type, member) ( \
(type *) (char *)(ptr)-offsetof(type,member)\
)
Run Code Online (Sandbox Code Playgroud)
此代码段是否符合ISO标准(因此应该能够在任何符合标准的编译器上编译)?
Jon*_*ler 16
正如Ouah评论的那样,({ ... })语句表达式是GNU扩展; 你将无法使用它.您的核心表达式接近所需,但没有足够的括号:
#define container_of(ptr, type, member) \
((type *) ((char *)(ptr) - offsetof(type, member)))
Run Code Online (Sandbox Code Playgroud)
这看起来很干净.SO只分布在两条线上.
Chr*_*oph 12
宏的编写方式是执行类型检查ptr.可以使用复合文字而不是语句表达式,__typeof__如果编译器不兼容gcc,则可以回退到指针的简单检查而不是使用:
#ifdef __GNUC__
#define member_type(type, member) __typeof__ (((type *)0)->member)
#else
#define member_type(type, member) const void
#endif
#define container_of(ptr, type, member) ((type *)( \
(char *)(member_type(type, member) *){ ptr } - offsetof(type, member)))
Run Code Online (Sandbox Code Playgroud)