通過成員變數位址獲取結構體位址

2021-06-20 16:30:37 字數 1737 閱讀 4187

linux中有乙個巨集

#define container_of(ptr,type,member) 實現略
實現了通過成員變數位址獲取結構體位址的功能。

今天我想好好想想這個實現的原理是怎麼來的。

先定義乙個結構體吧

typedef struct

abc;

再來設計乙個函式用來實現功能

int main(void)

main()剛剛好,嘿嘿

輸出結果為

abc : 0022ff44

abc.c : 0022ff4c

如何求得這個差呢?

可以這樣,把abc的乙個例項對映到0這個位址,這樣成員c的位址就是在0的基礎上網上加,進而此時成員c的位址

就是它們的差值

這樣printf("%u\n",&(((abc*)0)->c));

不過編譯,執行後會crash掉,因為0這個位址被printf檢測到是非法位址,所以得這樣

printf("%u\n",(size_t)&(((abc*)0)->c));
這樣,傳給printf的引數不是乙個位址,而是乙個普通的常數

好,那麼可以求abc位址了

printf("%p\n",&(abc.c) - (size_t)&(((abc*)0)->c));
執行,結果是

abc : 0022ff2c
和abc的位址不對啊,為什麼呢?

因為此處&(abc.c)這一句有問題。指標的加減操作的步長是按照這個指標的型別來定的,此處c是int型,則它 - 8,其實位址是 - 8 * sizeof(int).

你看,0022ff2c是不是比0022ff44少24.就是因為它上面的操作多減了24

所以,得這樣

printf("abc : %p\n",(unsigned char*)&(abc.c) - (size_t)&(((abc*)0)->c));
輸出結果為

abc : 0022ff44
ok,目標達成。

現在用巨集封裝一下

#define container_in(ptr,type,member) \

(type*)((unsigned char*)(ptr) - (size_t)&(((type*)0)->member))

把差值強制轉換為(type*)是因為這個巨集的目的就是返回(type*)型別的指標

做個測試

#include #include #include #define container_in(ptr,type,member) \

(type*)((unsigned char*)(ptr) - (size_t)&(((type*)0)->member))

typedef struct

test1;;

typedef struct

test2;;

typedef struct

abc;

int main(void)

輸出結果

1 2 4

謝謝觀賞!

C語言 結構體變數位址

includetypedef struct student stu intmain 陣列名 陣列位址 陣列第乙個元素的位址 陣列第乙個元素的第乙個成員的位址 printf 張三位址 d n edu printf 張三位址 d n edu printf 張三位址 d n edu 0 printf 張三...

考考你 根據結構體變數位址反推結構體首位址

考考你 根據結構體變數位址反推結構體首位址 2011 07 21 16 51 38 標籤 結構體 首位址container of offsetof 偏移最近在看 linux核心設計與實現 這本書,感覺寫得非常棒,看第6章 核心資料結構 的時候,遇到兩個非常牛b的巨集,據此簡單地設計乙個考題,以便分析...

檢視變數位址

在linux中寫乙個程式,裡面全域性變數,區域性變數,static,const,常數,陣列,輸出這些變數的位址 包括賦值的和沒有賦值的,各類資料型別 如下 include int a int b 1 int const c 1 int const x static int d static int ...