1. 程式人生 > >關於container_of函式分析

關於container_of函式分析

#include <stdio.h>

#define offset_of(type,member) ((int)&(((type *)0)->member))

#define container_of(ptr,type,member) ({\    
    const typeof(((type*)0)->member) *__mptr = ptr;\    
    (type *)((char *)__mptr - offset_of(type,member));\
    })

struct mytest{
    char i;
    
int j; char *k; }; int main(){ struct mytest temp; struct mytest *p; printf("&temp = %p\n",&temp); printf("&temp.k = %p\n",&temp.k); printf("&((struct mytest *)0)->k = %d\n",((int)&((struct mytest *)0)->k)); printf("&temp = %p \n
",container_of(&temp.j,struct mytest,j)); printf("&temp = %p \n",container_of(&temp.k,struct mytest,k)); return 0;}
View Code

(一).分析下巨集定義1:

#define offset_of(type,member) ((int)&(((type *)0)->member))

     (type * )0 :強制把0地址轉化為type *型別

     &(((type *)0)->member) :將type型別的member成員的地址取出。這裡用法很妙,由於type指標地址是0,故其成員地址都是基地址為0加上偏移地址。

     (int)(&(((type *)0)->member)) :將type成員型別地址強制轉化為int。

 

(二).分析下巨集定義2:

#define container_of(ptr,type,member) ({\	
    const typeof(((type*)0)->member) *__mptr = ptr;\
    (type *)((char *)__mptr - offset_of(type,member));\
    })

       2.1. 分析 const typeof(((type *)0)->member) *__mptr = ptr;

                 const typeof(((type *)0)->member) :typeof是關鍵字,獲取成員型別。此部分是得到巨集傳過來的成員型別。

                 const typeof(((type *)0)->member) *__mptr = ptr :此部分為什麼要重新定義__mptr呢?這就是寫linux核心工程師的牛逼,嚴謹之處。如果開發者使                用時輸入的引數有問題:ptr與member型別不匹配,編譯時便會有warnning, 但是如果去掉改行,那個就沒有了,而這個警告恰恰是必須的(防止出錯有不              知道錯誤在哪裡)。。。

       2.2. 分析(type *)((char *)__mptr - offset_of(type,member));

                (char *)__mptr :將成員型別強制轉化為char *,如此地址進行加減時以位元組為單位

                (char *)__mptr - offset_of(type,member) :計算出結構體首地址,此時地址型別為char *

              (type *)((char *)__mptr - offset_of(type,member)):將char * 強制轉化為(type *)

 

索引文獻:https://blog.csdn.net/s2603898260/article/details/79371024