1.container_of巨集
1 > Container_of在Linux核心中是一個常用的巨集,用於從包含在某個結構中的指標獲得結構本身的指標,通俗地講就是通過結構體變數中某個成員的首地址進而獲得整個結構體變數的首地址。
2 > 介面:
container_of(ptr, type, member)
ptr:表示結構體中member的地址
type:表示結構體型別
member:表示結構體中的成員
通過ptr的地址可以返回結構體的首地址
3 > container_of的實現:
1 2 3 |
#define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );}) |
其實它的語法很簡單,只是一些指標的靈活應用,它分兩步:
第一步,首先定義一個臨時的資料型別(通過typeof( ((type *)0)->member )獲得)與ptr相同的指標變數__mptr,然後用它來儲存ptr的值。
說明:typeof是GNU C對標準C的擴充套件,它的作用是根據變數獲取變數的型別《typeof關鍵字在linux 核心中很常見》
第二步,用(char *)__mptr減去member在結構體中的偏移量,得到的值就是整個結構體變數的首地址(整個巨集的返回值就是這個首地址)。
關於offsetof的用法可參見offsetof巨集的使用。
2. 舉例來說明 container_of 的使用
1 > 正確示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <stdio.h> #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );}) struct test_struct { int num; char ch; float f1; }; int main(void) { struct test_struct *test_struct; struct test_struct init_struct ={12,'a',12.3}; char *ptr_ch = &init_struct.ch; test_struct = container_of(ptr_ch,struct test_struct,ch); printf("test_struct->num =%d\n",test_struct->num); printf("test_struct->ch =%c\n",test_struct->ch); printf("test_struct->ch =%f\n",test_struct->f1); return 0; } |
執行結果:
1 2 3 4 |
jibo@jibo-VirtualBox:~/cv_work/work/list/container_of $ ./main test_struct->num =12 test_struct->ch =a test_struct->ch =12.300000 |
2 > 錯誤示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <stdio.h> #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) #define container_of(ptr, type, member) ({ const typeof( ((type *)0)->member ) *__mptr = (ptr); (type *)( (char *)__mptr - offsetof(type,member) );}) struct test_struct { int num; char ch; float f1; }; int main(void) { struct test_struct *test_struct; char real_ch = 'A'; char *ptr_ch = &real_ch; test_struct = container_of(ptr_ch,struct test_struct,ch); printf("test_struct->num =%d\n",test_struct->num); printf("test_struct->ch =%c\n",test_struct->ch); printf("test_struct->ch =%f\n",test_struct->f1); return 0; } |
執行結果為:
1 2 3 4 |
jibo@jibo-VirtualBox:~/cv_work/work/list/container_of1 $ ./main test_struct->num =0 test_struct->ch =A test_struct->ch =0.000000 |
注意,由於這裡並沒有使用一個具體的結構體變數,所以成員num和f1的值是不確定的。