C 程式設計/stddef.h/offsetof
外觀
C 的 offsetof() 宏是 ANSI C 庫中的一個功能,它存在於stddef.h中。它計算給定成員在一個結構體或聯合體型別中的偏移量(以位元組為單位),表示式型別為size_t。該offsetof() 宏接受兩個引數,第一個是結構體名稱,第二個是結構體中成員的名稱。它不能被描述為 C 原型。[1]
該宏的“傳統”實現依賴於編譯器對指標的處理並不特別挑剔;它透過指定一個從地址零開始的假設結構體來獲取成員的偏移量
#define offsetof(st, m) \
((size_t) ( (char *)&((st *)(0))->m - (char *)0 ))
這是透過將空指標強制轉換為指向結構體的指標來實現的st,獲取結構體中成員m的地址,將該地址強制轉換為字元指標,然後使用指標算術來減去結構體的基地址,所有這些都導致結構體開頭和成員開頭之間的字元位置(即位元組)數量。
雖然這在許多編譯器中都能正確工作,但根據 C 標準,它具有未定義的行為,因為它涉及空指標的解引用和違反別名規則的強制轉換。如果其中一個引數拼寫錯誤,它也會導致令人困惑的編譯器診斷。現代編譯器通常使用特殊形式定義宏,例如[2]
#define offsetof(st, m) __builtin_offsetof(st, m)
它在 C 中實現通用資料結構時很有用。例如,Linux 核心使用offsetof()來實現container_of(),它允許類似於 Mixin 型別的結構找到包含它的結構體:[3]
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
此宏用於從指向巢狀元素的指標中檢索包含結構體,例如此迴圈遍歷my_struct物件的連結串列
struct my_struct {
const char * name;
struct list_node list;
};
extern struct list_node * list_next(struct list_node *);
struct list_node * iter = /* ... */
while (iter)
{
struct my_struct * elem = container_of(iter, struct my_struct, list);
printf("%s\n", elem->name);
iter = list_next(&elem->list);
}
- ↑ "offsetof reference". MSDN. Retrieved 2010-09-19.
- ↑ "GCC offsetof reference". Free Software Foundation. Retrieved 2010-09-19.
- ↑ Greg Kroah-Hartman (2003-06). "container_of()". Linux Journal. Retrieved 2010-09-19.
{{cite web}}: Check date values in:|date=(help)