#define OffSet(type,field) ((size_t)&(((type*)0)->field))
在C語言中,ANSI C標準允許值爲0的常量被強制轉換成任何一種類型的指針,而且轉換結果是一個空指針,即NULL指針,因此對0取指針的操作((type*)0)的結果就是一個類型爲type*的NULL指針。 但是如果利用這個NULL指針來訪問type類型的成員當然是非法的。
因爲&(((type*)0)->field)的意圖只不過是計算field字段的地址,C語言編譯器根本不生成訪問type成員的代碼,而僅僅是根據type的內容佈局和結構體實例地址在編譯期計算這個常量地址,這樣就完全避免了通過NULL指針訪問內存可能出現的問題。同時又因爲結構體地址是0,所以字段地址的值就是字段相對於結構體基址的偏移。
程序示例如下:
#include <stdio.h>
#define OffSet(type,field) ((size_t)&(((type*)0)->field))
struct Mystr{
char a;
short b;
double c;
int d;
};
int main()
{
printf("%d\n",OffSet(struct Mystr,a));
printf("%d\n",OffSet(struct Mystr,b));
printf("%d\n",OffSet(struct Mystr,c));
printf("%d\n",OffSet(struct Mystr,d));
return 0;
}
程序運行結果爲(32位機器,char佔一個字節,short佔兩個字節,double佔8個字節,int佔4個字節):
0
2
8
16
結果分析:
上述方法避免了實例化一個type對象,而且求值是在編譯期間進行,沒有運行期負擔,程序效率大大提高。