container of巨集詳解

2021-07-11 20:12:09 字數 2861 閱讀 2161

//該巨集位於include/linux/kernel.h

1.定義格式

#define container_of(ptr, type, member)()

作用:就是根據乙個結構體變數中的乙個域成員變數的指標來獲取指向整個結構體變數的指標。

例:struct demo_struct

struct demo_struct demo1,*pdemo;

type2 * demo_member2=demo1.member2;

如果要得到demo1的指標,可以使用該巨集:

pdemo=container_of(demo_member2,struct demo_struct,member2);

2.巨集執行機理解析

typeof是gnu c對標準c的擴充套件,它的作用是根據變數獲取變數的型別。將上例中的巨集按照巨集定義進行展開,如下:

1 pdemo=()

從上面定義來看,**中的第2行的作用是首先使用typeof獲取結構體域變數member2的型別為type2,然後定義了乙個type2指標型別的臨時變數__mptr,並將實際結構體變數中的域變數的指標demo_member2的值賦給臨時變數__mptr。

第2行**實際上類似下面定義:

const type2 * __mptr=demo_member2;

這裡((struct demo_struct *)0)比較巧妙,它指的是structdemo_struct型變數位址為基位址,偏移量為0的位址,實際上就是struct demo_struct型變數位址。

第3行**中,(char *)__mptr轉換為位元組型指標。(char *)__mptr -offsetof(type,member) )用來求出結構體起始位址(為char *型指標),然後(type *)( (char*)__mptr - offsetof(type,member) )在(type *)作用下進行將位元組型的結構體起始指標轉換為type*型的結構體起始指標。

其中,offsetof巨集定義如下:

#define offsetof(type, member) ((size_t) &(((type*)0)->member)

可以看出,該巨集就是計算出type變數中member成員基位址。該巨集執行機理如下:

l ( (type *)0 )將零轉型為type型別指標;

l ((type *)0)->member訪問結構中的資料成員;

l &( ( (type *)0 )->member )取出資料成員的位址;

l (size_t)(&(((type*)0)->member))結果轉換型別。

該巨集巧妙之處在於將0轉換成(type*),如果結構體以記憶體空間首位址0作為起始位址,則成員位址自然為偏移位址;

__mptr - offsetof(struct demo_struct, member2)

type1 member1

type2 member2

type3 member3

offsetof(type,member)__mptr

__mptr - offsetof(struct demo_struct, member2)

type1 member1

type2 member2

type3 member3

offsetof(type,member)__mptr

還有一篇文章

在linux核心中經常可以看到container_of的身影,也是linux引以為豪的地方之一了。《linux裝置驅動開發詳解》132頁對container_of的作用作了說明——通過結構體成員的指標找到這個成員所在結構體的指標。但沒有具體分析它是怎麼實現的。

下面我們先看看這個巨集的定義:

#define container_of(ptr, type, member)()

引數ptr是結構體typ的成員member的指標,我們很多時候希望得到結構體type的起始位址,也就是type的指標。

假設這個type在記憶體中的儲存模型如下:

type

|----------|| |

| ||----------|

ptr->|  member --|

|----------|| |

| ||----------|

這裡,我們拆開來就好理解了:

首先,(type *)0)是把0位址轉化為type結構的指標(這裡把0換成其它值也是一樣的);

((type *)0)->member 

type結構體中的member成員;

typeof( ((type *)0)->member ) 返回member的型別;

const typeof( ((type *)0)->member ) *__mptr =(ptr);  用上面這個型別定義乙個指標__mptr,並把ptr賦值給它;

(char *)__mptr 

把__mptr轉化成char型指標;

offsetof巨集定義在[include/linux/stddef.h]中定義為:

#define offsetof(type, member) ((size_t) &((type*)0)->member)

這 裡,說明一下這個巨集,((size_t) &((type*)0)->member)把0位址轉化為type結構的指標,然後獲取該結構中member成員的指標,並將其強制轉換為size_t型別。於是,由於結構從0位址開始定義,因此,這樣求出的member成員位址,實際上就是它在結構中的偏移量。這也顯示出了c語言中指標的強大。因為,在某個體系結構下實現的libc,結構中各個成員的偏移總是可以預見的。

現在有了member成員在type結構體中的偏移量,又有了指向member的指標__mptr,自然就可以計算出type結構的起始位址了。

小小乙個巨集就包括了這麼多精華,可見linux的博大。

#linux

container of巨集定義

1 container of在linux核心中是乙個常用的巨集,用於從包含在某個結構中的指標獲得結構本身的指標,通俗地講就是通過結構體變數中某個成員的首位址進而獲得整個結構體變數的首位址。2 介面 container of ptr,type,member ptr 表示結構體中member的位址 ty...

Linux 核心巨集 container of

container of ptr,type,member arguments ptrthe pointer to the member.代表指標 type the type ofthe container struct this isembedded in.型別 member 成員變數 the na...

container of巨集實現原理

ptr 指向例項化的結構體元素member的指標 type 是這個結構體型別 member 結構體中乙個元素的元素名 1 type 0 member 將0位址定義成乙個type型別指標,這個指標就可以訪問這個型別裡面的任意元素了 2 typeof type 0 member 得到這個元素的資料型別 ...