内核的“container_of” - 任何办法让它符合ISO?(Kernel's “co

2019-06-23 20:24发布

虽然看着Linux内核的实现双向链表圆形名单,我发现下面的宏:

#define container_of(ptr, type, member) ({           \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

其工作原理是返回指针安排其成员之一的只给出地址:

struct blabla
{
    int value;
    struct list_head *list;
}

因此,你可以得到指针布拉布拉(并获得“值”)给出的只有指针列表。 我的问题,我怎么会做出这种尽可能实现可移植性(最好的情况下,符合C89 / C99?)。 由于typeof运算()的使用,这仅仅是GCC。

这是我到目前为止有:

#define container_of(ptr, type, member) (                  \
                (type *) (char *)(ptr)-offsetof(type,member)\
                )

难道这个片段符合ISO标准(因此应该能够在任何符合编译器编译)?

Answer 1:

如Ouah评论的,所述({ ... })语句表达是GNU扩展; 你将无法使用。 你的核心表现是接近真实需要什么,但是没有足够的括号:

#define container_of(ptr, type, member) \
                      ((type *) ((char *)(ptr) - offsetof(type, member)))

这看上去干净给我。 这只是两行流传这么久。



Answer 2:

宏写它是perfom一个类型检查的方式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)))


Answer 3:

ISO C90兼容版本的类型检查。 (但是, 需要注意:两种评估ptr !)

#define container_of(ptr, type, member) \
   ((type *) ((char *) (ptr) - offsetof(type, member) + \
              (&((type *) 0)->member == (ptr)) * 0))

struct container {
  int dummy;
  int memb;
};


#include <stddef.h>
#include <stdio.h>

int main()
{
  struct container c;
  int *p = &c.memb;
  double *q = (double *) p;
  struct container *pc = container_of(p, struct container, memb);
  struct container *qc = container_of(q, struct container, memb);
  return 0;
}

测试:

$ gcc -Wall containerof.c
containerof.c: In function ‘main’:
containerof.c:20:26: warning: comparison of distinct pointer types lacks a cast
containerof.c:20:21: warning: unused variable ‘qc’
containerof.c:19:21: warning: unused variable ‘pc’

我们得到了distinct pointer types为26的警告,而不是25。关于被滥用的指针是我们的诊断。

我首先尝试将所述类型检查到逗号操作者的左手侧,GCC抱怨具有没有影响,这是一个麻烦。 但是,使它成为一个操作数,我们确保其使用。

&((type *) 0)->member特技不能很好地由ISO C定义的,但它被广泛用于定义offsetof 。 如果你的编译器对这个空指针招offsetof ,它几乎肯定会表现自己在自己的宏。



文章来源: Kernel's “container_of” - any way to make it ISO conforming?