介紹一下list中的關鍵函數container_of:
/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) /
container_of(ptr, type, member)
關於container_of見kernel.h中:
/**
* 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) ({ /
const typeof( ((type *)0)->member ) *__mptr = (ptr); /
(type *)( (char *)__mptr - offsetof(type,member) );})
container_of在Linux Kernel中的應用非常廣泛,它用於獲得某結構中某成員的入口地址.
關於offsetof見stddef.h中:
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
TYPE是某struct的類型 0是一個假想TYPE類型struct,MEMBER是該struct中的一個成員. 由於該struct的基地址為0, MEMBER的地址就是該成員相對與struct頭地址的位移量.
關於typeof,這是gcc的C語言擴充保留字,用於聲明變數類型.
const typeof( ((type *)0->member ) *__mptr = (ptr);意思是聲明一個與member同一個類型的指標常量 *__mptr,並初始化為ptr.
(type *)( (char *)__mptr - offsetof(type,member) );意思是__mptr的地址減去member在該struct中的位移量得到的地址, 再轉換成type型指標. 該指標就是member的入口地址了.
舉例說明:
約定: 地址由高向低分配, 分配後指標指向高地址, 結構按逆序由高向低儲存, 不做對齊處理.
struct snow
{
char name; // 1
int size; // 4
time_t hold; // 16
};
struct snow *p = (struct snow)malloc(sizeof(struct snow));
上面我們已經在堆中0x121至0x101分配了一個snow的struct, 並用p指標指向這段記憶體位址.
如果我們想取得p指向的結構中size變數的入口地址, 可以用container_of(p, struct snow, size);
這個調用的步驟是:
1` 取得p的指標地址, 121
2` 取得size在struct中的位移量, 16
3` 相減獲得size的入口地址, 105
通過這一個簡單的例子應該能理解container_of的工作原理了, 這隻是一個模仿的例子, 具體實現原理請參考ULK中的記憶體管理.