list_entry 解析

原文地址:http://www.cnblogs.com/lsjoo-dream/articles/2089150.html

list_entry的宏定義:
#define list_entry(ptr, type, member) \ 
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
這個倒是不難理解:從一個結構的成員指針找到其容器的指針。
但是正因爲如此,我的第一感覺是,這個宏的名字應該更加抽象,名字似乎應該改稱叫“尋找容器”一類的,查看list.h源代碼,發現現在的定義是這樣的:
#define list_entry(ptr, type, member) \
    container_of(ptr, type, member)

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

#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
linux不想用C++,但又想利用C++的優點,如是出現了很多奇怪的宏,他們叫做trick。
ptr是找容器的那個變量的指針,把它減去自己在容器中的偏移量的值就應該得到容器的指針。(容器就是包含自己的那個結構)。指針的加減要注意類型,用(char*)ptr是爲了計算字節偏移。((type*)0)->member是一個小技巧。自己理解吧。前面的(type *)再轉回容器的類型。
=====================
#define list_entry(ptr, type, member) \
        ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))

    ptr是指向list_head類型鏈表的指針,type爲一個結構,而member爲結構type中的一個域,類型爲list_head,這個宏返回指向type結構的指針。在內核代碼中大量引用了這個宏,因此,搞清楚這個宏的含義和用法非常重要。

  
設有如下結構體定義:
typedef struct xxx
{
     ……(結構體中其他域,令其總大小爲size1)
     type1 member;
     ……(結構體中其他域)
}type;


定義變量:
   type a;
   type * b;
   type1 * ptr;
執行:
   ptr=&(a.member);
   b=list_entry(ptr,type,member);
則可使b指向a,得到了a的地址

如何做到的呢?

先看&((type *)0)->member:
把“0”強制轉化爲指針類型,則該指針一定指向“0”(數據段基址)。因爲指針是“type *”型的,所以可取到以“0”爲基地址的一個type型變量member域的地址。那麼這個地址也就等於member域到結構體基地址的偏移字節數。

 


再來看 ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))):
(char*)(ptr)使得指針的加減操作步長爲一字節,(unsigned long)(&((type*)0)->member)等於ptr指向的member到該member所在結構體基地址的偏移字節數。二者一減便得出該結構體的地址。轉換爲(type *)型的指針,大功告成。

==============

 list_entry定義如下:

/**
* list_entry - get the struct for this entry
* @ptr:        the &struct list_head pointer.
* @type:        the type of the struct this is embedded in.
* @member:        the name of the list_struct within the struct.
*/
#define list_entry(ptr, type, member) \
        ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
===================

/**********************做出的簡單嘗試如下:************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#ifdef __compiler_offsetof
#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER)
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif

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

#define list_entry(ptr, type, member) container_of(ptr, type, member)
typedef struct listNode
{
    struct listNode *next;
    struct listNode *prev;
    int key;    //for search
} listNode;

typedef struct ListDemo{
    listNode *node;
    int member;
    }ListDemo;

int main(){
    listNode list;
    list.prev=list.next=NULL;
    list.key=1;
   
    ListDemo demo;
    demo.node=&list;
    demo.member=111;
   
    ListDemo *p;
    listNode *ptr=&list;
    p=list_entry(ptr,ListDemo,node);
    getch();
    return 1;
    }


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