轉自:http://blog.csdn.net/npy_lp/article/details/7010752
開發平臺:Ubuntu11.04
? ? 編 譯器:gcc version 4.5.2 (Ubuntu/Linaro4.5.2-8ubuntu4)
?
? ? Container_of在Linux內核中是一個常用的宏,用于從包含在某個結構中的指針獲得結構本身的指針,通俗地講就是通過結構體變量中某個成員的首地址進而獲得整個結構體變量的首地址。
? ? Container_of的定義如下:?
- #define?container_of(ptr,?type,?member)?({??????\??
- ????const?typeof(?((type?*)0)->member?)?*__mptr?=?(ptr);????\??
- ????(type?*)(?(char?*)__mptr?-?offsetof(type,member)?);})??
? ? 其實它的語法很簡單,只是一些指針的靈活應用,它分兩步:
? ? 第一步,首先定義一個臨時的數據類型(通過typeof( ((type *)0)->member )獲得)與ptr相同的指針變量__mptr,然后用它來保存ptr的值。
? ? 第二步,用(char *)__mptr減去member在結構體中的偏移量,得到的值就是整個結構體變量的首地址(整個宏的返回值就是這個首地址)。
? ? 其中的語法難點就是如何得出成員相對結構體的偏移量?
? ? 通過例子說明,如清單1:?
- /*?linux-2.6.38.8/include/linux/compiler-gcc4.h?*/??
- #define?__compiler_offsetof(a,b)?__builtin_offsetof(a,b)??
- ??
- /*?linux-2.6.38.8/include/linux/stddef.h?*/??
- #undef?offsetof??
- #ifdef?__compiler_offsetof??
- #define?offsetof(TYPE,MEMBER)?__compiler_offsetof(TYPE,MEMBER)??
- #else??
- #define?offsetof(TYPE,?MEMBER)?((size_t)?&((TYPE?*)0)->MEMBER)??
- #endif??
- ??
- #include?<stdio.h>??
- ??
- struct?test_struct?{??
- ????int?num;??
- ????char?ch;??
- ????float?fl;??
- };??
- ??
- int?main(void)??
- {??
- ????printf("offsetof(struct?test_struct,?num)?=?%d\n",???
- ????????????offsetof(struct?test_struct,?num));??
- ??????
- ????printf("offsetof(struct?test_struct,??ch)?=?%d\n",???
- ????????????offsetof(struct?test_struct,?ch));??
- ??????
- ????printf("offsetof(struct?test_struct,??fl)?=?%d\n",???
- ????????????offsetof(struct?test_struct,?fl));??
- ??????
- ????return?0;??
- }??
? ? 說明,__builtin_offsetof(a,b)是GCC的內置函數,可認為它的實現與((size_t) &((TYPE *)0)->MEMBER)這段代碼是一致的。
? ? 例子輸出結果:?
- offsetof(struct?test_struct,?num)?=?0??
- offsetof(struct?test_struct,??ch)?=?4??
- offsetof(struct?test_struct,??fl)?=?8??
? ? 其中代碼難以理解的地方就是它靈活地運用了0地址。如果覺得&( (struct test_struct *)0 )->ch這樣的代碼不好理解,那么我們可以假設在0地址分配了一個結構體變量struct test_struct a,然后定義結構體指針變量p并指向a(struct test_struct *p = &a),如此我們就可以通過&p->ch獲得成員ch的地址。由于a的首地址為0x0,所以成員ch的首地址為0x4。
?
? ? 最后通過強制類型轉換(size_t)把一個地址值轉換為一個整數。
? ? 分析完container_of的定義,接下來舉兩個例子來體會一下它的使用方法。
? ? 正確的例子,如清單2:?
- /*?linux-2.6.38.8/include/linux/compiler-gcc4.h?*/??
- #define?__compiler_offsetof(a,b)?__builtin_offsetof(a,b)??
- ??
- /*?linux-2.6.38.8/include/linux/stddef.h?*/??
- #undef?offsetof??
- #ifdef?__compiler_offsetof??
- #define?offsetof(TYPE,MEMBER)?__compiler_offsetof(TYPE,MEMBER)??
- #else??
- #define?offsetof(TYPE,?MEMBER)?((size_t)?&((TYPE?*)0)->MEMBER)??
- #endif??
- ??
- /*?linux-2.6.38.8/include/linux/kernel.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)?);})??
- ??
- #include?<stdio.h>??
- ??
- struct?test_struct?{??
- ????int?num;??
- ????char?ch;??
- ????float?fl;??
- };??
- ??
- int?main(void)??
- {??
- ????struct?test_struct?init_test_struct?=?{?99,?'C',?59.12?};??
- ??
- ????char?*char_ptr?=?&init_test_struct.ch;??
- ??
- ????struct?test_struct?*test_struct?=?container_of(char_ptr,?struct?test_struct,?ch);??
- ??????
- ????printf("?test_struct->num?=?%d\n?test_struct->ch?=?%c\n?test_struct->fl?=?%f\n",???
- ????????test_struct->num,?test_struct->ch,?test_struct->fl);??
- ??????
- ????return?0;??
- }??
? ? 例子輸出結果:?
- test_struct->num?=?99??
- test_struct->ch?=?C??
- test_struct->fl?=?59.119999??
? ? 不適當的例子,如清單3:?
- /*?linux-2.6.38.8/include/linux/compiler-gcc4.h?*/??
- #define?__compiler_offsetof(a,b)?__builtin_offsetof(a,b)??
- ??
- /*?linux-2.6.38.8/include/linux/stddef.h?*/??
- #undef?offsetof??
- #ifdef?__compiler_offsetof??
- #define?offsetof(TYPE,MEMBER)?__compiler_offsetof(TYPE,MEMBER)??
- #else??
- #define?offsetof(TYPE,?MEMBER)?((size_t)?&((TYPE?*)0)->MEMBER)??
- #endif??
- ??
- /*?linux-2.6.38.8/include/linux/kernel.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)?);})??
- ??
- #include?<stdio.h>??
- ??
- struct?test_struct?{??
- ????int?num;??
- ????char?ch;??
- ????float?fl;??
- };??
- ??
- int?main(void)??
- {??
- ????char?real_ch?=?'A';??
- ????char?*char_ptr?=?&real_ch;??
- ??
- ????struct?test_struct?*test_struct?=?container_of(char_ptr,?struct?test_struct,?ch);??
- ??
- ????printf("?char_ptr?=?%p??test_struct?=?%p\n\n",?char_ptr,?test_struct);??
- ??
- ????printf("?test_struct->num?=?%d\n?test_struct->ch?=?%c\n?test_struct->fl?=?%f\n",???
- ????????test_struct->num,?test_struct->ch,?test_struct->fl);??
- ??????
- ????return?0;??
- }??
? ? 例子輸出結果:?
- char_ptr?=?0xbfb72d7f??test_struct?=?0xbfb72d7b??
- ??
- test_struct->num?=?-1511000897??
- test_struct->ch?=?A??
- test_struct->fl?=?0.000000??
? ? 注意,由于這里并沒有一個具體的結構體變量,所以成員num和fl的值是不確定的。