C語言中結構體偏移量的計算

     一、先來一段理論知識

        ANSI C標準允許任何值爲0的常量被強制轉換成任何一種類型的指針,並且轉換結果是一個NULL指針,因此((s*)0)的結果就是一個類型爲s*的NULL指針。如果利用這個NULL指針來訪問s的成員當然是非法的,但&(((s*)0)->m)的意圖並非想存取s字段內容,而僅僅是計算當結構體實例的首址爲((s*)0)時m字段的地址。聰明的編譯器根本就不生成訪問m的代碼,而僅僅是根據s的內存佈局和結構體實例首址在編譯期計算這個(常量)地址,這樣就完全避免了通過NULL指針訪問內存的問題。

        二、在實踐中檢驗理論

        下面是我在window環境下VS2008編譯器下的記錄,

       

  1. #include <stdlib.h>  
  2. #include <iostream>  
  3. using namespace std;  
  4.   
  5. typedef struct ISO_MSG  
  6. {  
  7.     char    msg_type[5];  
  8.     char    proc_code[7];  
  9. }ISO_MSG;  
  10.   
  11. #define fld_sizeof(s, m) sizeof(((s *)0)->m)  
  12. //#define offsetof(s,m) (( (size_t) &( ( (s*)0 )->m )) - (size_t)((s*)0))  
  13. #define offsetof1(s,m) ( (size_t) &( ( (s*)0 )->m ))  
  14.   
  15. int _tmain(int argc, _TCHAR* argv[])  
  16. {  
  17.     ISO_MSG sIsoMsg;  
  18.     memset((void*)&sIsoMsg,0,sizeof(ISO_MSG));  
  19.   
  20.     strcpy(sIsoMsg.msg_type,"0200");  
  21.     strcpy(sIsoMsg.proc_code,"000000");  
  22.   
  23.     cout << fld_sizeof(ISO_MSG,msg_type) << offsetof1(ISO_MSG,msg_type) << endl;  
  24.     cout << fld_sizeof(ISO_MSG,proc_code) << offsetof1(ISO_MSG,proc_code) << endl;  
  25.   
  26.     system("pause");  
  27.     return 0;  
  28. }  
#include <stdlib.h>
#include <iostream>
using namespace std;

typedef struct ISO_MSG
{
	char	msg_type[5];
	char	proc_code[7];
}ISO_MSG;

#define fld_sizeof(s, m) sizeof(((s *)0)->m)
//#define offsetof(s,m) (( (size_t) &( ( (s*)0 )->m )) - (size_t)((s*)0))
#define offsetof1(s,m) ( (size_t) &( ( (s*)0 )->m ))

int _tmain(int argc, _TCHAR* argv[])
{
	ISO_MSG sIsoMsg;
	memset((void*)&sIsoMsg,0,sizeof(ISO_MSG));

	strcpy(sIsoMsg.msg_type,"0200");
	strcpy(sIsoMsg.proc_code,"000000");

	cout << fld_sizeof(ISO_MSG,msg_type) << offsetof1(ISO_MSG,msg_type) << endl;
	cout << fld_sizeof(ISO_MSG,proc_code) << offsetof1(ISO_MSG,proc_code) << endl;

	system("pause");
	return 0;
}

        在上例中,存在兩個宏定義,fld_sizeof和offsetof;這兩個宏定義一個是計算結構成員變量字節大小,一個是計算偏移量,其中offsetof和offsetof1是等價的,

        三、系統的offsetof定義

         該宏在Linux內核代碼(版本2.6.22)中定義如下:
         /* Offset of member MEMBER in a struct of type TYPE. */
        #define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)


            在windows下,

           

  1. #ifdef  _WIN64  
  2. #define offsetof(s,m)   (size_t)( (ptrdiff_t)&reinterpret_cast<const volatile char&>((((s *)0)->m)) )  
  3. #else  
  4. #define offsetof(s,m)   (size_t)&reinterpret_cast<const volatile char&>((((s *)0)->m))  
  5. #endif  
  6.   
  7. #else  
  8.   
  9. #ifdef  _WIN64  
  10. #define offsetof(s,m)   (size_t)( (ptrdiff_t)&(((s *)0)->m) )  
  11. #else  
  12. #define offsetof(s,m)   (size_t)&(((s *)0)->m)  
  13. #endif  
#ifdef  _WIN64
#define offsetof(s,m)   (size_t)( (ptrdiff_t)&reinterpret_cast<const volatile char&>((((s *)0)->m)) )
#else
#define offsetof(s,m)   (size_t)&reinterpret_cast<const volatile char&>((((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
         四、參考內容

         http://www.jxva.com/blog/201202/335.html,這裏有非常詳細的說明,大家可以來這裏查看。

發佈了35 篇原創文章 · 獲贊 5 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章