zoukankan      html  css  js  c++  java
  • container_of学习笔记

    最近在学习c语言宏编程,看到了container_of宏,深入学习了一天,做个笔记留念。

    1、看一下书上写的container_of的版本:

    #define offsetof(TYPE,MEMBER)   ((size_t) &((TYPE *)0)->MEMBER)
    #define container_of(PTR,TYPE,MEMBER)    ({  
        const typeof(((TYPE *)0)->MEMBER) *__mptr=(PTR);  
        (TYPE *) ((char *)__mptr - offsetof(TYPE,MEMBER)); })

    2、举一个实例:

    int main(int argc, char *argv[])
    {
        struct test{
            int num;
            char ch; 
        }t1={100,'c'};
        char *pch=&t1.ch;
        struct test *ptt=container_of(pch,struct test,ch);
        printf("num=%d
    ",ptt->num);
    
        return 0;
    }

    替换后的结果:

    int main(int argc, char *argv[])
    {
     struct test{
      int num;
      char ch;
     }t1={100,'c'};
     char *pch=&t1.ch;
     struct test *ptt=({ const typeof(((struct test *)0)->ch) *__ptmp=(pch); (struct test *)((char *)__ptmp - ((size_t) &((struct test *)0)->ch)); });
     printf("num=%d
    ",ptt->num);
    
     return 0;
    }         

    如果替换后的结果你还能看懂,说明你是真明白了,呵呵,有没有兴趣自己写一遍替换后的代码?

    3、多余的不说了,网上有的是讲解的,这里就说二点:

       1、container_of宏第一步是做类型检查的,也就是检查ptr是否是指向结构成员member的,如果我们用typeof求出来的类型和ptr不一致,那么编译器会报错。为啥要做这个检查呢?因为ptr和member都是人工输入的参数,宏要保证它们是结构体成员和其相关联的指针,这个宏才有意义,所以类型检查是必须的。

          2、第二步相减时,把mptr指针强转成(char *)是因为,char指针减法只移一个字节,如果这样才可能得出准确的地址,否则,改为int类型,在减1就移动4个就乱了。

    4、我有研究了最新4.12kernel的该宏,发现有了变化:

    /**
     * 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) ({                
        void *__mptr = (void *)(ptr);                    
        BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) &&    
                 !__same_type(*(ptr), void),            
                 "pointer type mismatch in container_of()");    
        ((type *)(__mptr - offsetof(type, member)));

    哇,这里有出现一个新宏:__same_type,赶紧用ctags查一下定义,在include/linux/compiler.h中:

    /* Are two types/vars the same type (ignoring qualifiers)? */
    #ifndef __same_type
    # define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))                  
    #endi

    有2个新变化,显得更加高大上了,第一,用void *取代了char *来做减法,第二,用__same_type宏来做类型检测,显得更加的直观明了,错了还可以有提示。

  • 相关阅读:
    U盘为什么还有剩余空间,但却提示说空间不够
    U盘安装系统
    win8 64位+Oracle 11g 64位下使用PL/SQL Developer 的解决办法
    Oracle 去掉重复字符串
    ORACLE获取字符串中数字部分
    MyBatis中的大于、小于、like等符号写法
    Oracle计算时间差函数
    HDU 3569 Imaginary Date 简单期望
    C语言之——文件操作模式
    LeetCode OJ 之 Ugly Number II (丑数-二)
  • 原文地址:https://www.cnblogs.com/litifeng/p/7690585.html
Copyright © 2011-2022 走看看