linux中有乙個巨集
#define container_of(ptr,type,member) 實現略
實現了通過成員變數位址獲取結構體位址的功能。
今天我想好好想想這個實現的原理是怎麼來的。
先定義乙個結構體吧
typedef struct
abc;
再來設計乙個函式用來實現功能
int main(void)
main()剛剛好,嘿嘿
輸出結果為
不過編譯,執行後會crash掉,因為0這個位址被printf檢測到是非法位址,所以得這樣abc : 0022ff44
abc.c : 0022ff4c
如何求得這個差呢?
可以這樣,把abc的乙個例項對映到0這個位址,這樣成員c的位址就是在0的基礎上網上加,進而此時成員c的位址
就是它們的差值
這樣
printf("%u\n",&(((abc*)0)->c));
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 ...