container_of與offsetof詳解

Linxu內核中宏container_of的作用是根據結構體成員的一個指針地址來獲取整個結構體的地址,要想理解container_of,我們先來看看宏offsetof

我們先來看看宏offsetof

在Linux內核中是這樣定義的:
#ifndef _LINUX_STDDEF_H
#define _LINUX_STDDEF_H
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
一共4步
1. ( (TYPE *)0 ) 將零轉型爲TYPE類型指針;
2. ((TYPE *)0)->MEMBER 訪問結構中的數據成員;
3. &( ( (TYPE *)0 )->MEMBER )取出數據成員的地址;
4.(size_t)(&(((TYPE*)0)->MEMBER))結果轉換類型。巧妙之處在於將0轉換成(TYPE*),結構以內存空間首地址0作爲起始地址,則成員地址自然爲偏移地址;

再來看看宏container_of

在Linux內核中是這樣定義的:

#ifndef _LINUX_KERNEL_H
#define _LINUX_KERNEL_H
#include "stddef.h"
/**
* container_of - cast a member of a structure out to the containing structure
* @ptr: the pointer to the member.
* @type: the type of the container struct this is embedded in.
* @member: the name of the member within the struct.
*
*/
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#endif

其中,typeof是GNU C對標準C的擴展,它的作用是根據變量獲取變量的類型。因此,上述代碼中的第2行的作用是首先使用typeof獲取結構體域變量member的類型爲 type,然後定義了一個type指針類型的臨時變量__mptr,並將實際結構體變量中的域變量的指針ptr的值賦給臨時變量__mptr

第三行代碼分爲三步:

1.(char *)__mptr轉換爲字節型指針。

2.(char *)__mptr - offsetof(type,member) )用來求出結構體起始地址(爲char *型指針),

3.然後(type *)( (char *)__mptr - offsetof(type,member) )在(type *)作用下進行將字節型的結構體起始指針轉換爲type *型的結構體起始指針。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章