
#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;}
(一).分析下宏定義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