Offsetof巨集詳解

2021-09-29 18:18:05 字數 3710 閱讀 2105

c語言面試的時候可能會考,這樣的巨集定義:

#define offsetof(type, member) ((size_t) &((type*)0)->member)
函式作用:計算結構體成員的偏移,有些自有**裡也會手寫這樣的**,實際上這個函式是標準實現的。實際上如果我們瀏覽 ansi c 編譯器的標標頭檔案,將在 stddef.h 中遇到這樣奇怪的巨集。這個紅具有可怕的宣告。此外,如果您查閱編譯器手冊,您會發現乙個無益的解釋,上面寫著如下:

offsetof() 巨集返回結構或聯合復合中元素名稱的偏移量。這提供了一種可移植的方法來確定偏移量。

函式的宣告是這樣的

size_t offsetof(type, member);
函式描述:

offset巨集 從結構型別的開頭返回字段成員的偏移量。

此巨集很有用,因為組成結構的字段的大小可能因實現而異,並且編譯器可能在字段之間插入不同數量的填充位元組。因此,元素的偏移量不一定由前乙個元素的大小之和給出。

如果成員不與位元組邊界對齊(例如,它是位欄位),則會產生編譯器錯誤。

返回值:

返回給定型別中給定成員的偏移量(以位元組為單位)

標準:c89, c99, posix.1-2001

源**:

#include using namespace std;

int main()

; /* output is compiler dependent */

printf("sizeof(struct demo)=%ld\n", (long) sizeof(struct demo));

printf("offsets: a=%ld; b=%ld; c=%ld d=%ld\n",

(long)offsetof(struct demo, a),

(long)offsetof(struct demo, b),

(long)offsetof(struct demo, c),

(long)offsetof(struct demo, d));

exit(exit_success);

}

輸出結果:

sizeof(struct demo)=16

offsets: a=0; b=4; c=8 d=16

我們先來搞明白這個工作原理再看他到底有啥妙用。

offset的工作原理:

offset巨集的偏移量是 ansi 要求的巨集,應在 stddef.h 中找到。簡而言之,offset 巨集返回結構或聯合的特定元素之前的偏移位元組數。

巨集的宣告因**商而異,並且取決於處理器體系結構。

瀏覽各種編譯器,找到了一些清單示例宣告。

// keil 8051 compiler

#define offsetof(s,m) (size_t)&(((s *)0)->m)

// microsoft x86 compiler (version 7)

#define offsetof(s,m) (size_t)(unsigned long)&(((s *)0)->m)

// diab coldfire compiler

#define offsetof(s,memb) \

((size_t)((char *)&((s *)0)->memb-(char *)0))

//microsoft x86 compiler (version 2019)

#if defined _msc_ver && !defined _crt_use_builtin_offsetof

#ifdef __cplusplus

#define offsetof(s,m) ((::size_t)&reinterpret_cast((((s*)0)->m)))

#else

#define offsetof(s,m) ((size_t)&(((s*)0)->m))

#endif

#else

#define offsetof(s,m) __builtin_offsetof(s,m)

#endif

無論實現如何,offset 巨集採用兩個引數。第乙個引數是結構名稱;第二個,結構元素的名稱。

為了更好地理解offset巨集的魔力,進一步來看定義的細節,巨集中的各種運算子按順序計算,以便執行以下步驟:

根據定義,結構本身駐留在位址 0。因此,指向的字段(上述步驟 3)的位址必須是結構開頭的偏移量(以位元組為單位)

結構體內嵌結構體的情況:

// sytax.cpp : 此檔案包含 "main" 函式。程式執行將在此處開始並結束。

//#include using namespace std;

int main()

; typedef struct

sbar;

typedef struct

sfoo;

/* output is compiler dependent */

printf("offset of 'l' is %u \n", offsetof(sfoo, b.l));

printf("sizeof(struct demo)=%ld\n", (long) sizeof(struct demo));

printf("offsets: a=%ld; b=%ld; c=%ld d=%ld\n",

(long)offsetof(struct demo, a),

(long)offsetof(struct demo, b),

(long)offsetof(struct demo, c),

(long)offsetof(struct demo, d));

exit(exit_success);

}

知識點:結構填充位元組

大多數 16 位和更大的處理器要求在多位元組(例如,16 位或 32 位)邊界上對齊記憶體中的資料結構。有時,要求是絕對的,有時只是建議以獲得最佳匯流排吞吐量。在後一種情況下,之所以提供靈活性,是因為設計人員認識到,您可能希望將記憶體訪問時間與其他相互競爭的問題(如記憶體大小和傳輸能力(可能通過通訊鏈路或直接記憶體訪問)進行權衡。記憶體內容直接到具有不同對齊要求的另乙個處理器。

7 // 根據"結構體(type)變數"中的"域成員變數(member)的指標(ptr)"來獲取指向整個結構體變數的指標

8 #define container_of(ptr, type, member) ()

擴充套件:

一般編譯器是按照8位元組對齊的。如果改變對齊位元組,可以看到偏移有變化

#pragma pack(push) // 將當前pack設定壓棧儲存

#pragma pack(2)// 必須在結構體定義之前使用

struct demo;

#pragma pack(pop) // 恢復先前的pack設定

輸出結果:

sizeof(struct demo)=14

offsets: a=0; b=4; c=6 d=14

offsetof 巨集定義的詳解

define offsetof type,member size t type 0 member 在這裡我們解釋一下這個巨集定義,0我們知道 和null 一樣的意思 但是為什莫上面的表示式可以執行,我們知道操作乙個空指標不是會segment fault 嗎?這裡就要解釋一下了 這個巨集 並不是時我們...

核心第一巨集 offsetof詳解

offsetof是linux核心中乙個非常重要的巨集。它的主要作用就是求結構體重某個成員在結構體重的位置偏移。其實現如下 define offsetof type,member size t type 0 member type 0 member指向結構體中member成員變數。對其取位址 type...

關於offsetof巨集

offsetof 巨集 這是在看書的時候遇到的,估計以後會用到,避免遺忘,先記下來吧。一般形式 define offsetof type,member size t type 0 member 說明 通過 type 0 將0位址強制轉換為type結構型別中的指標 通過 type 0 member 訪...