container_of

container_of的函數實現:

  1. #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)  
  2. /** 
  3.  * container_of - cast a member of a structure out to the containing structure 
  4.  * @ptr:    the pointer to the member. 
  5.  * @type:   the type of the container struct this is embedded in. 
  6.  * @member: the name of the member within the struct. 
  7.  * 
  8.  */  
  9. #define container_of(ptr, type, member) ({          \  
  10.     const typeof(((type *)0)->member)*__mptr = (ptr);    \  
  11.              (type *)((char *)__mptr - offsetof(type, member)); })  

關於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 student結構體,初始化一個stu,container_of的作用是,知道stu中一個成員的地址,算出stu這個結構體的地址。如知道stu->sex的地址,返回stu的地址

分三步完成:

(1)得到結構體成員  物理地址   如得到:sut->sex

const typeof(((type *)0)->member)*__mptr = (ptr);

(2)得到成員在結構體中的偏移量 ,如上圖得到  在sturct student中,成員sex的  偏移量爲 20

offsetof(type,member)

(3)得到stu的  物理地址  ,如上圖得到  sut = stu->sex - 20  ,這樣就完成了返回stu物理地址。 

(type *)( (char *)__mptr - offsetof(type,member) )

下面看一個實例程序:

  1. #include<stdio.h>  
  2. struct student{  
  3.         char name[20];  
  4.         char sex;  
  5.         int num;  
  6. }stu= {"mingming",'m',101};  
  7. main()  
  8. {  
  9.         struct student *stu_ptr;  
  10.         int offset;  
  11.         const typeof(((struct student*)0)->sex) *_mptr = &stu.sex;//(1)得到成員_mptr= stu->sex的物理地址  
  12.                 printf("_mptr= 0x%d\n",_mptr);  
  13.         
  14.   offset = (int)(&((struct student *)0)->sex);//(2)成員在結構體中絕對偏移量  
  15.                 printf("offset = %d\n",offset);  
  16.   
  17.         stu_ptr = (struct student *)((char*)_mptr - offset);//(3)得到結構體stu 的物理地址  
  18.             printf("stu_ptr = 0x%d\n",stu_ptr);  
  19.         
  20.   printf("stu_ptr->name:%s\tstu_ptr->sex:%c\n", stu_ptr->name, stu_ptr->sex);  
  21.         return 0;  
  22. }        
container_of可以分解爲上面程序中的三步完成:

(1)得到成員_mptr= stu->sex的物理地址

首先定義一個 _mptr指針, 類型爲struct student結構體中sex成員的類型,typeof 爲獲取(((struct student*)0)->sex)的類型,此處此類型爲char,((struct student*)0)在offsetof處講解

(2)成員在結構體中絕對偏移量

((struct student*)0)爲 把 0地址 強制轉化爲指向student結構體類型的指針,該指針從地址 0 開始的 21個字節用來存放name 與 sex(char name〔20〕與 char sex共21字節),sex存放在第20個字節出(從0字節開始),&((struct student *)0)->sex 取出sex地址(此處即爲20) 並強制轉化爲整形,所以offset爲20,後面的printf結果將證明這一點

(3)得到結構體stu 的物理地址

((char*)_mptr - offset)此處先把_mptr指針轉化爲字符形指針,(爲什麼這麼做呢? 如果_mptr爲整形指針 _mptr - offset 相當於減去 sizeof(int)*offset個字節),減去 offset值 相當於 得到_mptr所在結構體的首地址(即stu的地址),然後我們把 該地址 強制轉化爲 struct student類型即可正常使用了

上面程序運行結果爲:

  1. root@android-virtual-machine:/uniteq_smb/test# ./teset_conta   
  2. _mptr= 0x134520872  
  3. offset = 20  
  4. stu_ptr = 0x134520852  
  5. stu_ptr->name:mingming   stu_ptr->sex:m  

發佈了16 篇原創文章 · 獲贊 3 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章