container_of(ptr, type, member)

來源:互聯網
上載者:User

 

指標ptr指向結構體type中的成員member;通過指標ptr,返回結構體type的起始地址

#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)
1.ptr為物理地址,其類型和member類型一致,最終使用typeof( ((type *)0)->member )
  由編譯器自動返回member的類型
2.type為包含member成員的結構體
3.offsetof(type,member)為member成員在type結構體中的位移值,大小範圍0~sizeof(type)位元組 (因為以0地址為type類型資料結構的起始地址)
4.ptr- offsetof()就等於包含該ptr的type結構體父變數的物理起始地址,強制轉換為(type*).

應用舉例:

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

#define list_for_each_entry(pos, head, member)                \
    for (pos = list_entry((head)->next, typeof(*pos), member);\
     prefetch(pos->member.next), &pos->member != (head);      \
     pos = list_entry(pos->member.next, typeof(*pos), member))
//-------------------------------------------------------------
list_entry((head)->next, typeof(*pos), member)返回(head)->next物理指標所處位置向前減去offsetof()個位元組資料之後, 其父變數pos的物理地址,父變數的類型在編譯時間由typeof(*pos)自動返回(gliethttp).
所以list_for_each_entry遍曆head下面掛接的類型為typeof(*pos)的childs結構體們,當然每個child結構體包含struct list_head node之類相似的雙向鏈表list_head類型項,就這樣通過迴圈pos將依次指向雙向鏈表上的各個child.(member就是child類型中被定義的變數名)
//-------------------------------------------------------------
下面一段程式摘自: drivers/usb/driver.c
struct usb_dynids {
    spinlock_t lock;
    struct list_head list;
};
struct usb_dynid {
    struct list_head node;
    struct usb_device_id id;
};
static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *intf,
                            struct usb_driver *drv)
{
    struct usb_dynid *dynid;

    spin_lock(&drv->dynids.lock);
//1. drv->dynids.list為head,即:樹根,父親,正如上面的struct usb_dynids
//2. dynid為child,其中drv->dynids.list.next存放了第一個child結構體中的
//   struct list_head類型名字為node的物理地址值.
//3. 看著很複雜,其實翻譯出來就簡單多了(gliethttp)
//模型為for(child;child != head;child = child->next)
// for(dynid = container_of(drv->dynids.list.next, struct usb_dynid,nod);
//     dynid->node != &drv->dynids.list;
//     dynid = container_of(dynid->node.next, struct usb_dynid,nod)
//     )
    list_for_each_entry(dynid, &drv->dynids.list, node) {
        if (usb_match_one_id(intf, &dynid->id)) {
            spin_unlock(&drv->dynids.lock);
            return &dynid->id;
        }
    }
    spin_unlock(&drv->dynids.lock);
    return NULL;
}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.