内核的"container_of" - 任何使ISO符合标准的方法吗?

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只分布在两条线上.

  • 实际上,应该提到的是,Linux内核使用非标准C的唯一原因是改进了编译时错误检查. (3认同)

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)

  • 只是一个小建议:`void` 应该改为`const void`,这样如果`ptr` 是const 限定的,那么编译器就不会抱怨丢弃`const` 限定符。 (2认同)