跳轉到內容

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);
}

參考文獻

[編輯 | 編輯原始碼]
  1. "offsetof reference". MSDN. Retrieved 2010-09-19.
  2. "GCC offsetof reference". Free Software Foundation. Retrieved 2010-09-19.
  3. Greg Kroah-Hartman (2003-06). "container_of()". Linux Journal. Retrieved 2010-09-19. {{cite web}}: Check date values in: |date= (help)
華夏公益教科書