container_of实例
1 前面說的
container_of 在linux內核代碼里面使用非常多,對于喜歡linux編程的同學來說,對這個函數要非常清楚他的使用方法,而且還要知道他的原理,這對以后看內核代碼,寫內核驅動的幫助都非常大,當然,我不是說了解這個就可以為所欲為了,內核博大精深,先宏觀再微觀去學習,不要想著一口就能吃成一個胖子,我這篇文章主要剖析一下這個函數的實現原理,希望對大家學習過程中有所幫助。
?
2 container_of的作用
container_of的作用的通過結構體成員變量地址獲取這個結構體的地址,就比如可以通過你的名字從而知道你爸爸的名字,比如別人叫你“李光明的兒子”,然后別人就可以知道你爸爸叫做“李光明”。
內核函數調用常常給函數傳入的是結構體成員地址,然后在函數里面又想使用這個結構體里面的其他成員變量,所以就引發了這樣的問題,我認為這個也是用C實現面向對象編程的一種方法。
比如這段代碼
early_suspend是sensor_private_data 里面的一個成員變量,通過這個成員變量的地址獲取sensor_private_data結構體變量的地址,從而調用里面的成員變量client。這個方法非常優雅。在這里我用到了一個比較叼的詞,叫“優雅”。
3 如何使用container_of
container_of(ptr, type, member)
- ptr:表示結構體中member的地址 h
- type:表示結構體類型 struct sensor_private_data
- member:表示結構體中的成員 early_suspend type里面一定要有這個成員,不能瞎搞啊
- 返回結構體的首地址
4 container_of 用到的知識點 剖析
4.1、({})
({}),第一個先說這個表達式,很多人可能懂,但是可能很多人沒見過,這個表達式返回最后一個表達式的值。
舉個例子
4.2、typeof
這個我們很少看到,這個關鍵字是C語言關鍵字的拓展,返回變量的類型,具體可以看GCC里面的介紹
https://gcc.gnu.org/onlinedocs/gcc/Typeof.html
例子:
4.3. 0的作用
尺子大家應該都用過吧,比如我想用尺子量一本書本的長度,我們第一時間就需要找到尺子的0刻度的位置,然后用這個0刻度的位置去對準書本的邊,然后再貼合對齊,在書本的另一邊查看尺子刻度就可以知道書本的長度了。
現在我們需要量一個結構體的長度,我們也可以用尺子來量,我們只要找到這個0刻度的位置就可以了。同理,即使我們不知道0刻度位置,我們首尾刻度相減一樣可以計算出結構體的長度。
上面的代碼
(struct?st*)0這個的意思就是把這個結構體放到0刻度上面開始量了,然后量到哪里呢?
&((struct?st*)0)->b)這個就體現出來了,量到b的位置。所以上面的輸出應該是4。
看完上面的解釋,應該知道下面這兩個代碼的功能是一樣的。
typeof?((struct?st*)0)->b)?c;?//?取b的類型來聲明c int?c;其實不只是對于0,用其他數字一樣是有效的,比如下面的代碼,并沒有任何問題,編譯器關心的是類型,而不在乎這個數字。
printf("%p\n",&((struct?st*)4)->b??-4?);4.4 offsetof(TYPE, MEMBER)
#define?offsetof(TYPE,?MEMBER)?((size_t)?&((TYPE*)0)->MEMBER)size_t 這個有不懂的可以百度下,就是unsigned 的整數,在32位和64位下長度不同,所以這個offsetof就是獲取結構體的偏移長度。
5 container_of 剖析
#define?offsetof(TYPE,?MEMBER)?((size_t)?&((TYPE*)0)->MEMBER) #define?container_of(ptr,?type,?member)?({??????????\const?typeof(?((type?*)0)->member?)?*__mptr?=?(const?typeof(?((type?*)0)->member?)?*)(ptr);?\(type?*)(?(char?*)__mptr?-?offsetof(type,member)?);}) //-----分割線 struct?st{int?a;int?b; }*pt; //用這個來舉例 container_of(&pt->a,struct?st,a)const?typeof(?((struct?st?*)0)->a?)?*__mptr?=?(const?typeof(?((struct?st?*)0)->a?)?*)(&pt->a); const?int?*__mptr?=?(int?*)(&pt->a);//第一句解析完,實際上就是獲取a的地址。 (type?*)(?(char?*)__mptr?-?offsetof(type,member)?); //這個變成 (struct?st?*)(?(char?*)__mptr?-?((unsigned?int)?&((struct?st*)0)->a)); //這句的意思,把a的地址減去a對結構體的偏移地址長度,那就是結構體的地址位置了。我畫個圖
?
6 實例代碼
/*************************************************************************>?File?Name:?4.c>?Author:?>?Mail:?>?Created?Time:?Mon?14?Jan?2019?04:47:24?PM?CST************************************************************************/#include<stdio.h> #include<stddef.h> #include<stdlib.h>#define?offsetof(TYPE,?MEMBER)?((size_t)?&((TYPE*)0)->MEMBER)/*ptr?成員指針 *?type?結構體?比如struct?Stu *?member?成員變量,跟指針對應 *?*/ #define?container_of(ptr,?type,?member)?({??????????\const?typeof(?((type?*)0)->member?)?*__mptr?=?(const?typeof(?((type?*)0)->member?)?*)(ptr);?\(type?*)(?(char?*)__mptr?-?offsetof(type,member)?);})typedef?struct?Stu{int?age;char?name[10];int?id;unsigned?long?phone_num; }*p_stu,str_stu;void?print_all(void?*p_str) {p_stu?m1p_stu?=?NULL;m1p_stu?=?container_of(p_str,struct?Stu,age);printf("age:%d\n",m1p_stu->age);printf("name:%s\n",m1p_stu->name);printf("id:%d\n",m1p_stu->id);printf("phone_num:%d\n",m1p_stu->phone_num); }void?main(void) {p_stu?m_stu?=?(p_stu)malloc(sizeof(str_stu));m_stu->age?=?25;m_stu->id??=?1;m_stu->name[0]='w';m_stu->name[1]='e';m_stu->name[2]='i';m_stu->name[3]='q';m_stu->name[4]='i';m_stu->name[5]='f';m_stu->name[6]='a';m_stu->name[7]='\0';m_stu->phone_num=13267;/*傳結構體成員指針進去*/print_all(&m_stu->age);printf("main?end\n");if(m_stu!=NULL)free(m_stu); }程序輸出
age:25 name:weiqifa id:1 phone_num:13267 main?end總結
以上是生活随笔為你收集整理的container_of实例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python定时启动任务_python-
- 下一篇: 一点小思考