用一個宏定義FIND求一個結構體struct裡某個變數相對struc的編移量.
如:stuct student
{
int a;
char b[20];
double ccc;
}
則:
FIND(student,a); //等於0
FIND(student,b);//等於4
#define FIND( struc, e ) (size_t)&(((struc*)0)- >e)
(struc*)0----------表示將常量0強制轉化為struc *型指標所指向的地址
&(((struc*)0)- >e)--表示取結構體指標(struc*)0的成員e的地址,因為該結構體的首地址為0,所以其實就是得到了成員e距離結構體首地址的位移量.
(size_t)-----------是一種資料類型,為了便於不同系統之間移植而定義的一種無符號型資料,一般為unsigned int
(struc*)0 表示假設在0地址處有一個結構體struc
((struc*)0)- >e 表示在0地址處的結構體struc的成員e
&(((struc*)0)- >e) 表示在0地址處的結構體struc的成員e 的地址
(size_t)&(((struc*)0)- >e) 將0地址處的結構體struc的成員e 的地址轉換成整數類型
#define OFFSETOF(type, field) ((size_t)&(((type *)0)->field))
(type *)0:把0地址當成type類型的指標。
((type *)0)->field:對應域的變數。
&((type *)0)->field:取該變數的地址,其實就等於該域相對於0地址的位移量。
(size_t)&(((type *)0)->field):將該地址(位移量)轉化為size_t型資料。
ANSI C標準允許任何值為0的常量被強制轉換成任何一種類型的指標,並且轉換結果是一個NULL指標,因此((s*)0)的結果就是一個類型為s*的NULL指 針。如果利用這個NULL指標來訪問s的成員當然是非法的,但&(((s*)0)->m)的意圖並非想存取s欄位內容,而僅僅是計算當結構 體執行個體的首址為((s*)0)時m欄位的地址。聰明的編譯器根本就不產生訪問m的代碼,而僅僅是根據s的記憶體布局和結構體執行個體首址在編譯期計算這個(常 量)地址,這樣就完全避免了通過NULL指標訪問記憶體的問題。