zoukankan      html  css  js  c++  java
  • linux内核宏之———container_of

    一、

    1 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)


    1. ( (TYPE *)0 ) 将零转型为TYPE类型指针;
    2. ((TYPE *)0)->MEMBER 访问结构中的数据成员;
    3. &( ( (TYPE *)0 )->MEMBER )取出数据成员的地址;
    4.(size_t)(&(((TYPE*)0)->MEMBER))结果转换类型;
    巧妙之处在于将0转换成(TYPE*),结构以内存空间首地址0作为起始地址,则成员地址自然为偏移地址。
    举例说明:

     1 #include<stdio.h>
     2 typedef struct _test
     3 {
     4       char i;
     5       int j;
     6       char k;
     7 }Test;
     8 
     9 int main()
    10 {
    11       Test *p = 0;
    12       printf("%p
    ", &(p->k));
    13 }

    答案:00000008
    自己分析:这里使用的是一个利用编译器技术的小技巧,即先求得结构成员变量在结构体中的相对于结构体的首地址的偏移地址,然后根据结构体的首地址为0,从而得出该偏移地址就是该结构体变量在该结构体中的偏移,即:该结构体成员变量距离结构体首的距离。在offsetof()中,这个member成员的地址实际上就是type数据结构中member成员相对于结构变量的偏移量。对于给定一个结构,offsetof(type,member)是一个常量,list_entry()正是利用这个不变的偏移量来求得链表数据项的变量地址。

    二、container_of()
    container_of() 来自linuxkernel.h

     1 /**
     2  * container_of - cast a member of a structure out to the containing structure
     3  * @ptr:    the pointer to the member.
     4  * @type:    the type of the container struct this is embedded in.
     5  * @member:    the name of the member within the struct.
     6  *
     7  */
     8 #define container_of(ptr, type, member) ({            
     9     const typeof( ((type *)0)->member ) *__mptr = (ptr);    
    10     (type *)( (char *)__mptr - offsetof(type,member) );})

    内核代码中看着不方便,整理一下便是如下:

    /**
     * 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));        
        }                                                            
    )

    自己分析:
    1.(type *)0->member为设计一个type类型的结构体,起始地址为0,编译器将结构体的起始的地址加上此结构体成员变量的偏移得到此结构体成员变量的偏移地址,由于结构体起始地址为0,所以此结构体成员变量的偏移地址就等于其成员变量在结构体内的距离结构体开始部分的偏移量。即:&(type *)0->member就是取出其成员变量的偏移地址。而其等于其在结构体内的偏移量:即为:(size_t)(& ((type *)0)->member)经过size_t的强制类型转换后,其数值为结构体内的偏移量。该偏移量这里由offsetof()求出。
    2.typeof( ( (type *)0)->member )为取出member成员的变量类型。用其定义__mptr指针.ptr为指向该成员变量的指针。__mptr为member数据类型的常量指针,其指向ptr所指向的变量处。
    3.(char *)__mptr转换为字节型指针。(char *)__mptr - offsetof(type,member))用来求出结构体起始地址(为char *型指针),然后(type *)( (char *)__mptr -offsetof(type,member) )在(type *)作用下进行将字节型的结构体起始指针转换为type *型的结构体起始指针。
    4.({ })这个扩展返回程序块中最后一个表达式的值。
          这就是通过结构体某成员变量的地址(指针)来求出该结构体变量的地址(指针)。这个宏返回结构体(外层)类型的指针。

  • 相关阅读:
    SQL Server 日期函数:某天是星期几?
    DZNEmptyDataSet,优秀的空白页或者出错页封装
    SVN文件排除
    Android开发艺术探索读书笔记——进程间通信
    HDU 2110 Crisis of HDU
    Android4.4之后休眠状态下Alarm不准时的问题
    Android App性能測试
    Java笔试面试题整理第一波
    美国大学计算机专业
    js 開始时间,当前时间,结束时间的比較
  • 原文地址:https://www.cnblogs.com/cmembd/p/3493526.html
Copyright © 2011-2022 走看看