linux內核container_of宏定義分析

一、#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER )
1. ( (TYPE *)0 ) 將零轉型爲TYPE類型指針;
2. ((TYPE *)0)->MEMBER 訪問結構中的數據成員;
3. &( ( (TYPE *)0 )->MEMBER )取出數據成員的地址;
4.(size_t)(&(((TYPE*)0)->MEMBER))結果轉換類型;
巧妙之處在於將0轉換成(TYPE*),結構以內存空間首地址0作爲起始地址,則成員地址自然爲偏移地址。
舉例說明:
#include<stdio.h>
typedef struct _test
{
      char i;
      int j;
      char k;
}Test;
int main()
{
      Test *p = 0;
      printf("%p\n", &(p->k));
}
答案:00000008
自己分析:這裏使用的是一個利用編譯器技術的小技巧,即先求得結構成員變量在結構體中的相對於結構體的首地址的偏移地址,然後根據結構體的首地址爲0,從而得出該偏移地址就是該結構體變量在該結構體中的偏移,即:該結構體成員變量距離結構體首的距離。在offsetof()中,這個member成員的地址實際上就是type數據結構中member成員相對於結構變量的偏移量。對於給定一個結構,offsetof(type,member)是一個常量,list_entry()正是利用這個不變的偏移量來求得鏈表數據項的變量地址。

二、container_of()

根據一個結構體變量中的一個域成員變量的指針來獲取指向整個結構體變量的指針;指針ptr指向結構體type中的成員member;通過指針ptr,返回結構體type的地址。

container_of() 來自\linux\kernel.h
內核中的註釋:container_of - cast a member of a tructure 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 truct.

#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

自己分析:
1.(type *)0->member爲設計一個type類型的結構體,起始地址爲0,編譯器將結構體的起始的地址加上此結構體成員變量的偏移得到此結構體成員變量的偏移地址,由於結構體起始地址爲0,所以此結構體成員變量的偏移地址就等於其成員變量在結構體內的距離結構體開始部分的偏移量。即:&(type *)0->member就是取出其成員變量的偏移地址。而其等於其在結構體內的偏移量:即爲:(size_t)(& ((type *)0)->member)經過size_t的強制類型轉換後,其數值爲結構體內的偏移量。該偏移量這裏由offsetof()求出。
2.typeof( ( (type *)0)->member )爲取出member成員的變量類型。用其定義__mptr指針.ptr爲指向該成員變量的指針。__mptr爲member數據類型的常量指針,其指向ptr所指向的變量處。
3.(char *)__mptr轉換爲字節型指針。(char *)__mptr - offsetof(type,member))用來求出結構體起始地址(爲char *型指針),然後(type *)( (char *)__mptr -offsetof(type,member) )在(type *)作用下進行將字節型的結構體起始指針轉換爲type *型的結構體起始指針。
4.({ })這個擴展返回程序塊中最後一個表達式的值。
      這就是從結構體某成員變量指針來求出該結構體的首指針。指針類型從結構體某成員變量類型轉換爲該結構體類型。

轉自:http://www.cnitblog.com/puppypyb/archive/2008/08/20/48172.aspx


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