Container_of在Linux內核中是一個常用的宏,用於從包含在某個結構中的指針獲得結構本身的指針,通俗地講就是通過結構體變量中某個成員的首地址進而獲得整個結構體變量的首地址。
實現方式:
container_of(ptr, type, member) ;
其實它的語法很簡單,只是一些指針的靈活應用,它分兩步:
第一步,首先定義一個臨時的數據類型(通過typeof( ((type *)0)->member )獲得)與ptr相同的指針變量__mptr,然后用它來保存ptr的值。
第二步,用(char *)__mptr減去member在結構體中的偏移量,得到的值就是整個結構體變量的首地址(整個宏的返回值就是這個首地址)。
其中的語法難點就是如何得出成員相對結構體的偏移量?
通過例子說明,如清單1:
1 #include <stdio.h> 2 #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) 3 #define container_of(ptr, type, member) ({ \ 4 const typeof( ((type *)0)->member ) *__mptr = (ptr); \ 5 (type *)( (char *)__mptr - offsetof(type,member) );}) 6 struct test_struct { 7 int num; 8 char ch; 9 float f1; 10 }; 11 int main(void) 12 { 13 struct test_struct *test_struct; 14 struct test_struct init_struct ={12,'a',12.3}; 15 char *ptr_ch = &init_struct.ch; 16 test_struct = container_of(ptr_ch,struct test_struct,ch); 17 printf("test_struct->num =%d\n",test_struct->num); 18 printf("test_struct->ch =%c\n",test_struct->ch); 19 printf("test_struct->ch =%f\n",test_struct->f1); 20 return 0; 21 }
或者Linux內核中的函數:
struct eg2805_charger { struct device *chg_dev; struct i2c_client *client; struct power_supply batt_psy; struct power_supply *usb_psy; struct workqueue_struct *chg_workqueue; struct delayed_work chg_delay_work; bool enable_chg; bool recharge; unsigned int chg_type; unsigned int battery_present; unsigned int online; unsigned int temperature; unsigned int voltage; unsigned int battery_status; unsigned int ichg; unsigned int aicr; unsigned int cv_value; unsigned int batt_current; struct qpnp_vadc_chip *vadc_dev; bool batt_hot; bool batt_warm; bool batt_cool; bool batt_cold; bool batt_good; int usb_psy_ma; struct mutex icl_set_lock; }; static void eg2805_charger_work(struct work_struct *work) { u8 buf[50]={0}; int i=0; int ret; int temp, voltage; int value = 0; //第一個參數為work,函數傳參下來的;第二個參數為定義的結構體,第三個則是傳參下來的里面需要的work_struct struct eg2805_charger *eg2805_chg = container_of(work, struct eg2805_charger, chg_delay_work.work);