例如
typedef struct struc {
int a;
char b[20];
double ccc;
};
現想要求 b 相對於 struc 的偏移地址。
其實,很早就知道有 (size_t)&(((struc*)0)->b) 這種寫法。昨天,捨友在第三版“面試寶典”上看到這種“怪異”寫法,過來問我是怎麼回事。
我呢,突然產生“用成員地址 - 結構體地址”的想法。試了一下。
printf("%d
", ((struc*)&(stc.b) - &stc)); // 居然輸出 0 !?
但是,分別計算 (struc*)&(stc.b) 和 &stc ,的確相差4字節。// 因為“.”比起地址“&”優先級高,所以 &(stc.b) 就是 &stc.b 。
百思不得其解。遂上論壇發問。答曰:“兩個指針相減的結果是兩指針的偏移量。這個偏移量是相對於指針類型來說的。比如兩int型指針相減,得出一個1,不代表二者地址值之差一個字節,這也是不可能的,因為int 類型一般來說是四字節。所以這個1指的是差的了1個 int 的大小(4字節)。同理, ((struc*)&(stc.b) - &stc) , 差的值還不足一個 struc 類型,自然就是 0 了。 如果想看地址差值,則將他們轉成數值類型:(intptr_t)&(stc.b) - (intptr_t)&stc 。” ( 原帖見 http://forum.byr.edu.cn/article/CPP/53484 )
恍然大悟!
遂改成
printf("%d
", ((stc.b) - (char*)&stc)); // ok!
printf("%d ", ((char*)(&stc.b) - (char*)&stc)); // 或許這種寫法更准確,如果確保 char 是一個字節的話。
又妄想的試了一下
printf("%d
", ((bool*)(&stc.b) - (bool*)&stc));
發現居然也是正確的 ?!
而後,又有高人答曰:“offsetof 一直就是 C 語言標准庫的一部分。直接用好了。”
標准庫?!心裡一驚。趕緊翻閱
裘宗燕.從問題到程序:程序設計與 C 語言引論.北京:機械工業出版社,2005.9,P372
書上曰:“文件<stddef.h> 裡包含了標准庫的一些常用定義,無論我們包含哪個標准頭文件,<stddef.h> 都會被自動包含進來。這個文件裡定義:......宏 offsetor ......”
offsetor ?! 難道是印刷錯誤? 我甚至還找到一篇犯同樣的錯誤的博客! 見 html">http://hi.baidu.com/esta_pessoa/blog/item/ffc91b3f225e95e755e72341.html
看來就是勘誤了,因為我的 VS2008 裡沒有 offsetor ,只有 offsetof 。還有,<stddef.h> 是要明確包含的,至少我的 VS2008 要求這樣。好了,趕緊試一下,
printf("%d
", offsetof(stc, stc.b)); // Error!
printf("%d
", offsetof(stc, b)); // 還是 Error!!!
無語。
查 C++ Reference ( http://www.cplusplus.com/reference ),居然要這樣
printf("%d
", offsetof(struc, b)); // !!!
雖然還有很多問題不明白,但求偏移地址就到這裡吧。
------------------------------------------------------------------------------------------------
總結一下,
對於一個結構體,例如
typedef struct struc {
int a;
char b[20];
double ccc;
};
想要求某一成員,例如 b ,相對於 struc 的偏移地址。
你可以:
// method 1 : 踩著前人的腳步
(size_t)&(((struc*)0)->b)
// method 2 : 站在巨人的肩膀上
offsetof(struc, b) // NOTE :要明確包含 <stddef.h> 頭文件
// method 3 : 走的人多了卻也成了路
(size_t)((char*)(&stc.b) - (char*)&stc)