ANSI C中取得結構體欄位偏移量的常用方法

2021-04-22 02:05:30 字數 1971 閱讀 5754

假設在ansi c程式中定義了乙個名為mystruct的結構型別,其中有乙個名為myfield的字段,如何取得它在結構體中的偏移?

typedef struct mystruct_tag

mystruct;

最容易想到的方法應該與如下**差不多:

size_t getoffset()

這段**確實能完成任務,但為了取得偏移值,函式不得不定義了乙個mystruct結構體例項,可這有必要嗎?仔細想想,結構體的記憶體布局是在什麼時候由誰決定的?沒錯,是編譯器在編譯期確定的,它一旦被確定就不會改變了,而依賴於結構體內存布局的字段偏移也就隨之確定並不再改變。既然在編譯階段編譯器就洞悉了內幕,那麼完全有理由要求它在編譯期為程式提供這些資訊。如何做呢?請看下面的**:

#define my_offset (size_t)&(((mystruct*)0)->myfield)

上面定義的my_offset巨集就是要的myfield的偏移。這樣強制轉換後的結構指標怎麼可以用來訪問結構體欄位?其實這個表示式根本沒有也不打算訪問myfield欄位。ansi c標準允許任何值為0的常量被強制轉換成任何一種型別的指標,並且轉換結果是乙個null指標,因此((mystruct*)0)的結果就是乙個型別為mystruct*的null指標。如 果利用這個null指標來訪問mystruct的成員當然是非法的,但&(((mystruct*)0)->myfield)的意圖並非想 訪問myfield欄位內容,而僅僅是計算當結構體例項的首址為((mystruct*)0)時myfield欄位的位址。聰明的編譯器根本就不生成訪問myfield的**,而僅僅是根據mystruct的記憶體布局和結構體例項首址在編譯期計算這個(常量)位址,這樣就完全避免了通過null指標訪問記憶體的問題。又因為首址的值為0,所以這個位址的值就是字段相對於結構體基址的偏移。

如上做法避免了一定要例項化乙個mystruct物件,並且求值是在編譯期進行,沒有執行期負擔。實際上這種利用編譯器掌握的整個程式的資訊以在編譯期計 算某些值的方法與現在c++程式設計中很流行的(靜態)元程式設計技術類似,只不過c++程式設計師可以利用模板技術在編譯期完成非常複雜的計算,而缺乏模板支援的 ansi c在這方面的能力則要弱許多。

或許因為求結構體欄位偏移很常用,ansi c在標準標頭檔案stddef.h中就專門定義了乙個形如offsetof(s,m)的巨集來求任意乙個結構型別中某個欄位的偏移,而且絕大多數c開發系統的實現都採用了上述的方法,例如:

// vc7.1

#ifdef  _win64

#define offsetof(s,m)   (size_t)( (ptrdiff_t)&(((s *)0)->m) )

#else

#define offsetof(s,m)   (size_t)&(((s *)0)->m)

#endif

//lcc-win32, last updated:monday, 13-dec-2004 04:05:23 est

#define offsetof(s,m) (int)&(((s *)0)->m)

//borland c++ 5.5.1 for win32

#define offsetof( s_name, m_name )  (_size_t)&(((s_name _far *)0)->m_name)

//mingw 3.1.0 (gcc 3.2.3)

#ifndef __cplusplus

#define offsetof(type, member) ((size_t) &((type *)0)->member)

#else /* c++ */

#define offsetof(type, member) (reinterpret_cast /

(&reinterpret_cast (static_cast (0)->member)))

#endif /* c++ */

可見這種簡練而有效的方法已被c程式設計師接納為一種慣用法(idiom)了。

結構體中的話題 偏移量

一旦結構體定義下來,則結構體中的成員,記憶體布局就定下來了。可以通過age位址,去求大的結構體的記憶體位址。如下 define crt secure no warnings include include include 一旦結構體定義下來,則結構體中的成員.記憶體布局 就定下了 可以通過 age位...

計算結構體偏移量

如果能夠讓 unsigned long type 的值為0,即 type 0的時候,那麼offset的值就是簡單的 offset unsigned long type.c 如果說 type 0,那麼type.c就可以等價於 type t 0 c。但是這個語句是不能單獨存在的,因為對null指標訪問成...

獲取結構體某成員偏移

本身這個問題非常簡單,直接用位址差值即可求得,最近在某本書上看到了乙個非常牛的方法,第一次看還將信將疑覺得不太可能,後面上機驗證發現確實可以,如下 1 include iostream 23 using namespace std 45 6struct test7 1314 define find ...