結構體之offsetof巨集詳細解析

2022-08-10 21:48:19 字數 2113 閱讀 2537

1、#define offsetof(type, member) ((size_t) &((type*)0)->member)     (include/linux/stddef.h)

1.1 功能:

返回結構體type中member成員相對於結構體首位址的偏移量,以位元組為單位。

1.2 解析:

此類複雜表示式的解析應該採用從內向外、逐層理解的方式。

首先,(type *)0表示將數字0強制型別轉換為type型別(type為結構體型別)的指標。因此這裡的0代表記憶體位址0,即我們認為記憶體位址0開始的sizeof(type)個位元組內儲存的是乙個type型別的變數。

然後,((type *)0)->member 得到該結構體變數中的member成員變數,

而 &(((type*)0)->member) 使用取位址符&取得了member成員變數的位址,(size_t)加在前面表示將member成員變數的位址強制型別轉換為size_t(即unsigned int),並將結果作為巨集的返回值。

可見,offsetof巨集返回的是member成員在記憶體中的實際位址。又因為整個結構體的起始位址是0,因此member成員的實際位址在數值上就等於member成員相對於結構體首位址的偏移量。

1.3 擴充套件思考:

1.3.1 使用offsetof巨集會影響記憶體0位址處的值嗎?

答案是不會,從1.3.2可知offsetof巨集的運算是在c編譯器編譯時完成的,因此記憶體的0位址在機器指令中根本未被操作,當然不會影響其值了。

1.3.2offsetof巨集返回的member相對於結構體首位址的偏移量是如何得到的?->符號如何能正確定址到結構體中某個成員變數?

想**struct如何通過->精確定址每乙個成員,最好的辦法就是將c**彙編為.s的組合語言**,通過觀察彙編**可以看到c編譯器對**處理的具體細節。我們的示例**如下:

#include"stdio.h"

#definemyoffsetof(type, member) ((size_t) &((type *)0)->member)

typedefstruct st

int a;

int c;     

//將該行加上或去掉,對比得到的彙編**的差別

short d;   //將該行加上或去掉,對比得到的彙編**的差別

char b;

}st;

intgetoffsetof(void)

return myoffsetof(struct st, b);

將以上**儲存為offsetof.c,並且使用arm-linux-gcc offsetof.c –s執行彙編,則會得到offsetof.s檔案,內容如下:

.file  "offsetof.c"

.text

.align 2

.global getoffsetof

.type  getoffsetof, %function

getoffsetof:

@ function supports interworking.

@ args = 0, pretend = 0, frame = 0

@ frame_needed = 1, uses_anonymous_args= 0

mov    ip, sp        // 這三行

stmfd  sp!,    // 是函式

sub    fp, ip, #4           // 棧幀儲存

mov    r3, #10          // #10即是offsetof巨集計算得到的值

mov    r0, r3        // 將返回值置於r0中

sub    sp, fp, #12      // 函式棧幀

ldmfd  sp,     // 恢復

bx     lr            // 函式返回

.size  getoffsetof, .-getoffsetof

.ident "gcc: (gnu) 4.1.2"

以上彙編**中mov r3, #10一句可以看出,offsetof巨集計算member的偏移量是c編譯器在編譯階段完成的,而並不需要cpu在執行時去計算得出。

可以嘗試著更改struct st中成員b之前的成員,然後再次彙編,對比彙編後**的不同,以此來驗證我們的推論。

結構體和巨集定義

問題 1.define?2.define m y y 3 y 3.巨集定義在 中?4.巨集定義允許巢狀?5.include 和 include 6.條件編譯?7.結構體?8.結構體賦初值?9.引用結構體變數中的成員?10.記憶體位元組對齊?解答 1.define 識別符號 字串 號開頭的都是預處理命...

結構體成員的偏移量與offsetof函式

1.一旦結構體定義下來,則結構體中的成員記憶體布局就定下了。typedef struct test testmem void test 2.offsetof函式 巨集函式offset,用於求結構體中的乙個成員,在結構體中的偏移量 在stddef.h 標頭檔案中,該巨集的完整說明如下 ifdef cp...

結構體指標 巨集 預編譯

1 陣列作為函式引數的時候,其實傳遞給函式的是陣列的首位址 2 指標 一次移動 乙個型別那麼長的距離 定義 指向結構體變數的指標 結構體指標 stustu2 stu o stu2 printf s o name p name 先通過指標找到指標指向的結構體變數,通過結構體變數對結構體成員進行操作 p...