1. 程式人生 > 實用技巧 >container_of巨集定義解析

container_of巨集定義解析

container_of巨集,定義kernel.h中:

 1 /**
 2 * container_of - cast a member of a structure out to the containing structure
 3 * @ptr:     the pointer to the member.
 4 * @type:     the type of the container struct this is embedded in.
 5 * @member:     the name of the member within the struct.
 6 *
 7 */
 8
#define container_of(ptr, type, member) ({ / 9 const typeof( ((type *)0)->member ) *__mptr = (ptr); / 10 (type *)( (char *)__mptr - offsetof(type,member) );})
container_of在Linux Kernel中的應用非常廣泛, 它用於從結構體成員獲取結構體的地址。定義中: typeof:這是gcc的C語言擴充套件保留字, 用於從變數獲取型別 offsetof在stddef.h中, 用來獲得一個結構體成員的相對偏移量
1
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
offsetof 是怎麼做到的呢?它把0地址強制轉化成了TYPE*型別,然後將它的MEMBER成員的地址轉化為size_t型別。也就是說如果一個型別為TYPE的結 構體地址從0開始,那麼它的MEMBER成員的地址就是MEMBER成員與TYPE型別地址之間的相對偏移量(以char計數的)。 開始解析container_of: 這個巨集傳入3個引數:ptr(type的成員的地址),type(結構體型別),member(成員的名稱) 第一行:const typeof( ((type *)0)->member ) *__mptr = (ptr); 首 先要正確的取得member地址,因為引數中沒有傳入member的型別,所以要通過typeof( ((type *)0)->member ) *搞出member的型別,typeof括號中的式子與offsetof中的作用類似,取得了member之後再使用typeof得到它的型別。所以第一 行的結果就是__mptr是member型別的指向ptr地址的常量指標。 第二行:(type *)( (char *)__mptr - offsetof(type,member) ); 取得了member的地址之後,只要把它減去member相對於結構體的偏移量,就可以得到結構體的地址了。最後,再把這個地址轉化成type*,就完成了整個邏輯。