zoukankan      html  css  js  c++  java
  • 考考你:根据结构体变量地址反推结构体首地址

    考考你:根据结构体变量地址反推结构体首地址
    2011-07-21 16:51:38
    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://ticktick.blog.51cto.com/823160/619824

         最近在看《Linux内核设计与实现》这本书,感觉写得非常棒,看第6章《内核数据结构》的时候,遇到两个非常牛B的宏,据此简单地设计一个考题,以便分析它们。

        【题目】:

        根据一个结构体某成员的名称和地址,以及结构体的类型,计算出该结构体对象的首地址。

        【例如】:

    1. struct A   
    2. {   
    3.     int x;   
    4.     int y;   
    5.     int z;   
    6. }   
    7.    
    8. #define GET_HEADER_ADDR(MEMBER_NAME,MEMBER_ADDR,STRUCT_TYPE) (你来实现)  
    9.    
    10. void main()   
    11. {   
    12.     struct A myTest;   
    13.    
    14.     int *pz = &myTest.z;  
    15.    
    16.     printf("addr is %d",GET_HEADER_ADDR(z,pz,struct A) );   
    17.    
    18. }  
     

        不看下面的答案,你来尝试实现上面这个宏吧。

     


        

    【答案与分析过程】

        Linux内核中,用两个非常巧妙地宏实现了,一个是offsetof宏,另一个是container_of宏,下面讲解一下这两个宏。

    1.  offsetof宏

    【定义】:#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER )

    【功能】: 获得一个结构体变量成员在此结构体中的偏移量。

    【例子】: 

    1. struct A 
    2.     int x ; 
    3.     int y; 
    4.     int z; 
    5. }; 
    6.  
    7. void main() 
    8.     printf("the offset of z is %d",offsetof( struct A, z )  ); 
    9.  
    10. // 输出结果为 8 
    【分析】:
     
    该宏,TYPE为结构体类型,MEMBER 为结构体内的变量名。
     
    (TYPE *)0) 是欺骗编译器说有一个指向结构TYPE 的指针,其地址值0 
     
    (TYPE *)0)->MEMBER 是要取得结构体TYPE中成员变量MEMBER的地址. 因为基址为0,所以,这时MEMBER的地址当然就是MEMBER在TYPE中的偏移了。
     
    2. container_of宏(即实现了题目中的功能
     
    【定义】:
     
    #define container_of(ptr, type, member)   ({const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );})
     
    【功能】:
     
    从结构体(type)某成员变量(member)指针(ptr)来求出该结构体(type)的首指针。
     
    【例子】:

    1. struct A 
    2.     int x ; 
    3.     int y; 
    4.     int z; 
    5. }; 
    6.  
    7. struct A myTest; 
    8.  
    9. int *pz = &myTest.z; 
    10.  
    11. struct A* getHeaderPtr( int *pz ) 
    12.     return container_of( pz , struct A, z ); 

     【分析】:

     (1) typeof( ( (type *)0)->member )为取出member成员的变量类型。

    (2) 定义__mptr指针ptr为指向该成员变量的指针(即指向ptr所指向的变量处)

    (3) (char *)__mptr - offsetof(type,member)) 用该成员变量的实际地址减去该变量在结构体中的偏移,来求出结构体起始地址。

    (4) ({ })这个扩展返回程序块中最后一个表达式的值。

     

    本文出自 “对影成三人” 博客,请务必保留此出处http://ticktick.blog.51cto.com/823160/619824

  • 相关阅读:
    Spring基础——小的知识点
    Spring总结—— IOC 和 Bean 的总结
    UML 类图
    Spring基础—— 泛型依赖注入
    Spring重点—— IOC 容器中 Bean 的生命周期
    Spring基础—— SpEL
    《大话设计模式》学习笔记13:适配器模式
    《大话设计模式》学习笔记12:状态模式
    《大话设计模式》学习笔记11:抽象工厂模式
    《大话设计模式》学习笔记10:观察者模式
  • 原文地址:https://www.cnblogs.com/ToDoToTry/p/2167608.html
Copyright © 2011-2022 走看看