程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> [C/C++]struct成員的偏移地址的求法

[C/C++]struct成員的偏移地址的求法

編輯:C++入門知識

例如
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)

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved