關於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;View Codeint 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;}
(一).分析下巨集定義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