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\n",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\n",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宏來做類型檢測,顯得更加的直觀明了,錯了還可以有提示。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM