我們假設結構體定義如下所示:
[cpp]view plain
copy
print?
#include
#include
struct
test_s
;
思路1: 非常簡單,直接用位址差值即可求得。
[cpp]view plain
copy
print?
intmain(
intargc,
char
*argv)
思路2: 考慮巨集定義的實現。(最佳思路!)
ansi c標準允許任何值為0的常量被強制轉換成任何一種型別的指標,並且轉換結果是乙個null指標,因此( (test_s*)0 )的結果就是乙個型別為test_s*的null指標。如果利用這個null指標來訪問s的成員當然是非法的,但&(((test_s*)0)->m)的意圖並非想訪問test_s欄位內容,而僅僅是計算當結構體例項的首址為((s*)0)時m欄位的位址。聰明的編譯器根本就不生成訪問m的**,而僅僅是根據test_s的記憶體布局和結構體例項首址在編譯期計算這個(常量)位址,這樣就完全避免了通過null指標訪問記憶體的問題。
[cpp]view plain
copy
print?
#define offset(type, member) (size_t)&( ((type*)0)->member) )
如上做法避免了一定要例項化乙個結構體物件,並且求值是在編譯期進行,沒有執行期負擔。因此是該問題的首選方案。
[cpp]view plain
copy
print?
intmain(
intargc,
char
*argv)
實際上這種利用編譯器掌握的整個程式的資訊以在編譯期計算某些值的方法與現在c++程式設計中很流行的(靜態)元程式設計技術類似,只不過c++程式設計師可以利用模板技術在編譯期完成非常複雜的計算,而缺乏模板支援的 ansi c在這方面的能力則要弱許多。
c++ 的實現:
[cpp]view plain
copy
print?
/* define offsetof macro */
#ifdef __cplusplus
#ifdef _win64
#define offsetof(s,m) (size_t)( (ptrdiff_t)&reinterpret_cast((((s *)0)->m)) )
#else
#define offsetof(s,m) (size_t)&reinterpret_cast((((s *)0)->m))
#endif
#else
#ifdef _win64
#define offsetof(s,m) (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#endif
#endif /* __cplusplus */
獲取結構體某成員偏移
本身這個問題非常簡單,直接用位址差值即可求得,最近在某本書上看到了乙個非常牛的方法,第一次看還將信將疑覺得不太可能,後面上機驗證發現確實可以,如下 1 include iostream 23 using namespace std 45 6struct test7 1314 define find ...
C C 結構體成員偏移量獲取
分析 節選自muduo.以下 通過offsetof獲取sin family在sockaddr in6中的字段偏移量.static assert offsetof sockaddr in6,sin6 family 0,sin6 family offset 0 需要注意 offsetof並非c c 標準...
從結構體成員獲取結構體位址的方法
今天朋友面試,有乙個問題他沒回答上來,我便在這裡給出答案,希望能幫助到一些準備找工作的同學。因為結構體成員在記憶體中的儲存資料是按照成員定義順序儲存的,因此,要回答這個問題,首先得解決兩個問題 意識到這兩個問題,還得注意兩個細節 1 c c 語言中,對指標進行算數運算時指標跳過的記憶體是 sizeo...