!!! 内核中的宏container_of
无    2017-03-24 09:10:43    399    0    0
simon88

container_of宏定义在linux内核的kernel.h头文件中有声明,他的目的是想计算出某个变量被包含在某个结构体中,这个结构体变量的地址。

container_of定义如下:

 */
#define container_of(ptr, type, member) ({			\
	const typeof( ((type *)0)->member ) *__mptr = (ptr);	\
	(type *)( (char *)__mptr - offsetof(type,member) );})
  • 第一步,首先定义一个临时的数据类型(通过typeof( ((type *)0)->member )获得)与ptr相同的指针变量__mptr,然后用它来保存ptr的值。
  • 第二步,用(char *)__mptr减去member在结构体中的偏移量,得到的值就是整个结构体变量的首地址(整个宏的返回值就是这个首地址)。

这里有一个难点就是如何可以找到成员member在这个结构体中的偏移量。

    /* linux-2.6.38.8/include/linux/compiler-gcc4.h */  
    #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)  
      
    /* linux-2.6.38.8/include/linux/stddef.h */  
    #undef offsetof  
    #ifdef __compiler_offsetof  
    #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)  
    #else  
    #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)  
    #endif  
      
    #include <stdio.h>  
      
    struct test_struct {  
        int num;  
        char ch;  
        float fl;  
    };  
      
    int main(void)  
    {  
        printf("offsetof(struct test_struct, num) = %d\n",   
                offsetof(struct test_struct, num));  
          
        printf("offsetof(struct test_struct,  ch) = %d\n",   
                offsetof(struct test_struct, ch));  
          
        printf("offsetof(struct test_struct,  fl) = %d\n",   
                offsetof(struct test_struct, fl));  
          
        return 0;  
    }  

例子输出结果: 

    offsetof(struct test_struct, num) = 0  
    offsetof(struct test_struct,  ch) = 4  
    offsetof(struct test_struct,  fl) = 8  

其中代码难以理解的地方就是它灵活地运用了0地址。如果觉得&( (struct test_struct *)0 )->ch这样的代码不好理解,那么我们可以假设在0地址分配了一个结构体变量struct test_struct a,然后定义结构体指针变量p并指向a(struct test_struct *p = &a),如此我们就可以通过&p->ch获得成员ch的地址。由于a的首地址为0x0,所以成员ch的首地址为0x4。

 

 

    最后通过强制类型转换(size_t)把一个地址值转换为一个整数。

    分析完container_of的定义,接下来举两个例子来体会一下它的使用方法。

    正确的例子,如清单2: 

    /* linux-2.6.38.8/include/linux/compiler-gcc4.h */  
    #define __compiler_offsetof(a,b) __builtin_offsetof(a,b)  
      
    /* linux-2.6.38.8/include/linux/stddef.h */  
    #undef offsetof  
    #ifdef __compiler_offsetof  
    #define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)  
    #else  
    #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)  
    #endif  
      
    /* linux-2.6.38.8/include/linux/kernel.h * 
     * container_of - cast a member of a structure out to the containing structure 
     * @ptr: the pointer to the member. 
     * @type:   the type of the container struct this is embedded in. 
     * @member:    the name of the member within the struct. 
     * 
     */  
    #define container_of(ptr, type, member) ({      \  
        const typeof( ((type *)0)->member ) *__mptr = (ptr);    \  
        (type *)( (char *)__mptr - offsetof(type,member) );})  
      
    #include <stdio.h>  
      
    struct test_struct {  
        int num;  
        char ch;  
        float fl;  
    };  
      
    int main(void)  
    {  
        struct test_struct init_test_struct = { 99, 'C', 59.12 };  
      
        char *char_ptr = &init_test_struct.ch;  
      
        struct test_struct *test_struct = container_of(char_ptr, struct test_struct, ch);  
          
        printf(" test_struct->num = %d\n test_struct->ch = %c\n test_struct->fl = %f\n",   
            test_struct->num, test_struct->ch, test_struct->fl);  
          
        return 0;  
    }  

例子输出结果: 

    test_struct->num = 99  
    test_struct->ch = C  
    test_struct->fl = 59.119999  

 

上一篇: C++ 类访问修饰符

下一篇: 变量

399 人读过
0 条评论