用宏定義FIND求一個結構體struct裏某個變量相對該結構體的編移量

原文:http://blog.sina.com.cn/s/blog_6867744f01017y7f.html

用一個宏定義FIND求一個結構體struct裏某個變量相對struc的編移量

如:struct student 

int a; 
char b; 
double c; 

則: 
FIND(struct student,a); //等於0 
FIND(struct student,b);//等於4

答案:#define FIND( struc, e ) (size_t)&(((struc*)0)- >e)

【疑問】:解答說(struc*)0 表示假設在0地址處有一個結構體struc,爲什麼說結構體struc的地址是0??

【參考文獻】:http://blog.csdn.net/wangyangkobe/article/details/5934093

                          http://blog.csdn.net/laurent1987/article/details/7658437

【解答】:0並不是結構體的地址,結構體在定義的時候並沒有分配內存空間,將0轉化成(struc*)類型的指針之後就相當於這塊有一個結構體變量,可以通過&(((struc*)0)- >e)來訪問地址,但是不能通過這個來訪問這塊內存,這樣不安全。

採用0這個地址是因爲,指針一般只能指向0這樣的隨意的地址,比如說隨意指向一個另外的值的地址
是不安全的。因爲對0指針刪除多次是安全的 。

首先,ANSI C標準允許任何值爲0的常量被強制轉換成任何一種類型的指針,並且轉換結果是一個NULL指針,所以我們的第一步(struc*)0,就是把0轉換爲一個struc類型的指針。利用這個訪問結構體裏面元素的話,是非法的。參考文獻:http://blog.csdn.net/huichengongzi/article/details/7478739 裏面提到:“&(((s*)0)->m)的意圖並非想存取s字段內容,而僅僅是計算當結構體實例的首址爲((s*)0)時m字段的地址。聰明的編譯器根本就不生成訪問m的代碼,而僅僅是根據s的內存佈局和結構體實例首址在編譯期計算這個(常量)地址,這樣就完全避免了通過NULL指針訪問內存的問題。”

(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 的地址轉換成整數類型​

2.

爲什麼要增加size_t呢?

首先size_t的定義是什麼呢,在文件 stddef.h中可以找到答案。

typedef unsigned int size_t;

可見就是將偏移量轉化爲無符整型,其實32位機器的地址就是無符號的32位整數。一般情況下,不進行size_t類型轉化也是沒有問題的(後面的實驗可證)。我認爲,只有偏移量足夠大,當大於 0x80000000時纔有影響,因爲這時候的偏移量最高位是1,機器默認爲是負數了。似乎上面宏定義OFFSETOF中更能說明這個問題,因爲這個宏定義是一個差值,最高位是1就肯定是負數了。使用printf("%d", &var);打印一個變量的地址就是個負數。這只是我的看法,網上基本沒有什麼人分析爲什麼添加size_t的強制類型轉化。因爲系統對數組長度的大小是有限制的,所以也不能實驗得到數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章