Linux驅動 container_of

來源:互聯網
上載者:User

--by FeCen
在學習Linux驅動的過程中,遇到一個很好玩的核心功能,準確的說是一個很好玩的宏,叫做container_of。該宏定義在include/linux/kernel.h中,首先來貼出它的代碼:

  1. 439/**
  2. 440 * container_of - cast a member of a structure out to the containing structure
  3. 441 * @ptr: the pointer to the member.
  4. 442 * @type: the type of the container struct this is embedded in.
  5. 443 * @member: the name of the member within the struct.
  6. 444 *
  7. 445 */
  8. 446#define container_of(ptr, type, member) ({ \
  9. 447 const typeof( ((type *)0)->member ) *__mptr = (ptr); \
  10. 448 (type *)( (char *)__mptr - offsetof(type,member) );})

它的作用顯而易見,那就是根據一個結構體變數中的一個域成員變數的指標來擷取指向整個結構體變數的指標。比如,有一個結構體變數,其定義如下:

  1. struct demo_struct {
  2. type1 member1;
  3. type2 member2;
  4. type3 member3;
  5. type4 member4;
  6. };
  7. struct demo_struct demo;

同時,在另一個地方,獲得了變數demo中的某一個域成員變數的指標,比如:

  1. type3 *memp = get_member_pointer_from_somewhere();

此時,如果需要擷取指向整個結構體變數的指標,而不僅僅只是其某一個域成員變數的指標,我們就可以這麼做:

  1. struct demo_struct *demop = container_of(memp, struct demo_struct, member3);

這樣,我們就通過一個結構體變數的一個域成員變數的指標獲得了整個結構體變數的指標。
下面說一說我對於這個container_of的實現的理解:
首先,我們將container_of(memp, struct demo_struct, type3)根據宏的定義進行展開如下:

  1. struct demo_struct *demop = ({ \
  2. const typeof( ((struct demo_struct *)0)->member3 ) *__mptr = (memp); \
  3. (struct demo_struct *)( (char *)__mptr - offsetof(struct demo_struct, member3) );})

其中,typeof是GNU C對標準C的擴充,它的作用是根據變數擷取變數的類型。因此,上述代碼中的第2行的作用是首先使用typeof擷取結構體域變數member3的類型為 type3,然後定義了一個type3指標類型的臨時變數__mptr,並將實際結構體變數中的域變數的指標memp的值賦給臨時變數__mptr。
假設結構體變數demo在實際記憶體中的位置如所示:
demo
+-------------+ 0xA000
| member1 |
+-------------+ 0xA004
| member2 |
| |
+-------------+ 0xA010
| member3 |
| |
+-------------+ 0xA018
| member4 |
+-------------+
則,在執行了上述代碼的第2行之後__mptr的值即為0xA010。
再看上述代碼的第3行,其中需要說明的是offsetof,它定義在include/linux/stddef.h中,其定義如下:

  1. 24#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)

同樣,我們將上述的offsetof調用展開,即為:

  1. (struct demo_struct *)( (char *)__mptr - ((size_t) &((struct demo_struct *)0)->member3) );

可見,offsetof的實現原理就是取結構體中的域成員相對於地址0的位移地址,也就是域成員變數相對於結構體變數首地址的位移。
因此,offsetof(struct demo_struct, member3)調用返回的值就是member3相對於demo變數的位移。結合上述給出的變數地址分布圖可知,offsetof(struct demo_struct, member3)將返回0x10。
於是,由上述分析可知,此時,__mptr==0xA010,offsetof(struct demo_struct, member3)==0x10。
因此, (char *)__mptr - ((size_t) &((struct demo_struct *)0)->member3) == 0xA010 - 0x10 == 0xA000,也就是結構體變數demo的首地址(如所示)。
由此,container_of實現了根據一個結構體變數中的一個域成員變數的指標來擷取指向整個結構體變數的指標的功能。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.