Kernel's “container_of” - any way to make it ISO conforming?

后端 未结 3 849
眼角桃花
眼角桃花 2020-12-17 14:36

While looking at Linux kernel\'s implementation of doubly linked circular lists, I\'ve found following macro:

#define container_of(ptr, type, member) ({              


        
3条回答
  •  一生所求
    2020-12-17 15:29

    ISO C90 compatible version with type check. (However, caveat: two evaluations of 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 
    #include 
    
    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;
    }
    

    Test:

    $ 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’
    

    We get the distinct pointer types warning for 26, but not 25. That is our diagnostic about pointers being misused.

    I first tried placing the type check into the left hand side of a comma operator, gcc complains about that having no effect, which is a nuisance. But by making it an operand, we ensure that it is used.

    The &((type *) 0)->member trick isn't well defined by ISO C, but it's widely used for defining offsetof. If your compiler uses this null pointer trick for offsetof, it will almost certainly behave itself in your own macro.

提交回复
热议问题