1. 程式人生 > >結構體對齊問題.

結構體對齊問題.

Intel、微軟等公司曾經出過一道類似的面試題:

2.1 自然對界

  struct是一種複合資料型別,其構成元素既可以是基本資料型別(如int、long、float等)的變數,也可以是一些複合資料型別(如array、struct、union等)的資料單元。對於結構體,編譯器會自動進行成員變數的對齊,以提高運算效率。預設情況下,編譯器為結構體的每個成員按其自然對界(natural alignment)條件分配空間。各個成員按照它們被宣告的順序在記憶體中順序儲存,第一個成員的地址和整個結構的地址相同。

自然對界(natural alignment)即預設對齊方式,是指按結構體的成員中size最大的成員對齊。

例如:

struct naturalalign
{
  char a;
  short b;
  char c;
};

在上述結構體中,size最大的是short,其長度為2位元組,因而結構體中的char成員a、c都以2為單位對齊,sizeof(naturalalign)的結果等於6;

如果改為:

struct naturalalign
{
  char a;
  int b;
  char c;
};

其結果顯然為12。

2.2指定對界

一般地,可以通過下面的方法來改變預設的對界條件:

使用偽指令#pragma pack (n),編譯器將按照n個位元組對齊;
使用偽指令#pragma pack (),取消自定義位元組對齊方式。

注意:如果#pragma pack (n)中指定的n大於結構體中最大成員的size,則其不起作用,結構體仍然按照size最大的成員進行對界。

例如:

#pragma pack (n)
struct naturalalign
{
 char a;
 int b;
 char c;
};
#pragma pack ()

當n為4、8、16時,其對齊方式均一樣,sizeof(naturalalign)的結果都等於12。而當n為2時,其發揮了作用,使得sizeof(naturalalign)的結果為8。

在VC++ 6.0編譯器中,我們可以指定其對界方式, 其操作方式為依次選擇projetct > setting > C/C++選單,在struct member alignment中指定你要的對界方式。

另外,通過__attribute((aligned (n)))也可以讓所作用的結構體成員對齊在n位元組邊界上,但是它較少被使用,因而不作詳細講解。

2.3 面試題的解答

  至此,我們可以對Intel、微軟的面試題進行全面的解答。

  程式中第2行#pragma pack (8)雖然指定了對界為8,但是由於struct example1中的成員最大size為4(long變數size為4),故struct example1仍然按4位元組對界,struct example1的size為8,即第18行的輸出結果;

  struct example2中包含了struct example1,其本身包含的簡單資料成員的最大size為2(short變數e),但是因為其包含了struct example1,而struct example1中的最大成員size為4,struct example2也應以4對界,#pragma pack (8)中指定的對界對struct example2也不起作用,故19行的輸出結果為16;

  由於struct example2中的成員以4為單位對界,故其char變數c後應補充3個空,其後才是成員struct1的記憶體空間,20行的輸出結果為4。

struct Size2{
 char c1;  
 int i1;    //佔4個位元組
 float f;

 double d1; //佔8個位元組
};
上邊的好像有點問題,這個sizeof()的結果是24;
目前可以這樣算,1+4+4+8 = 17;求大於17的8的最小倍數,那麼就是24了。


(看了下邊的,知道怎麼回事了,上邊我說的錯了)

struct Size2{
 char c1;   //下一個大小為4,偏移應該可以整除4,所以會填充3個位元組
 int i1;    //下一個大小為4,上邊的4加上int的大小4,所以這個偏移可以。佔4
 float f;  //下一個大小為8,當前正常偏移為12,不可以整除8,所以填充4位,偏移為16
 double d1; //佔8個位元組
};  //最後整體偏移為24,可以整除8。

下邊這個講的比較好

1 從union的sizeof問題看cpu的對界

考慮下面問題:(預設對齊方式)
union u
{
 double a;
 int b;
};
union u2
{
 char a[13];
 int b;
};
union u3
{
 char a[13];
 char b;
};

都知道union的大小取決於它所有的成員中,佔用空間最大的一個成員的大小。所以對於u來說,
大小就是最大的double型別成員a了,所以sizeof(u)=sizeof(double)=8。但是對於u2和u3,最
大的空間都是char[13]型別的陣列,為什麼u3的大小是13,而u2是16呢?關鍵在於u2中的成員
int b。由於int型別成員的存在,使u2的對齊方式變成4,也就是說,u2的大小必須在4的對界
上,所以佔用的空間變成了16(最接近13的對界)。

結論:複合資料型別,如union,struct,class的對齊方式為成員中對齊方式最大的成員的對
齊方式.順便提一下CPU對界問題,32的C++採用8位對界來提高執行速度,所以編譯器會盡量把
資料放在它的對界上以提高記憶體命中率。對界是可以更改的,使用#pragma pack(x)巨集可以改
變編譯器的對界方式,預設是8。C++固有型別的對界取編譯器對界方式與自身大小中較小的一
個。例如,指定編譯器按2對界,int型別的大小是4,則int的對界為2和4中較小的2。在預設的
對界方式下,因為幾乎所有的資料型別都不大於預設的對界方式8(除了long double),所以
所有的固有型別的對界方式可以認為就是型別自身的大小。更改一下上面的程式:


#pragma pack(2)
union u2
{
 char a[13];
 int b;
};
union u3
{
 char a[13];
 char b;
};

#pragma pack(8)


由於手動更改對界方式為2,所以int的對界也變成了2,u2的對界取成員中最大的對界,也是2了,所以此時sizeof(u2)=14。

結論:C++固有型別的對界取編譯器對界方式與自身大小中較小的一個。


9、struct的sizeof問題


因為對齊問題使結構體的sizeof變得比較複雜,看下面的例子:(預設對齊方式下)

struct s1
{
 char a;
 double b;
 int c;
 char d;
};

struct s2
{
 char a;
 char b;
 int c;
 double d;
};

同樣是兩個char型別,一個int型別,一個double型別,但是因為對界問題,導致他們的大小不同。
計算結構體大小可以採用元素擺放法,我舉例子說明一下:首先,CPU判斷結構體的對界,根據上
一節的結論,s1和s2的對界都取最大的元素型別,也就是double型別的對界8。然後開始擺放每個
元素。
對於s1,首先把a放到8的對界,假定是0,此時下一個空閒的地址是1,但是下一個元素d是double
型別,要放到8的對界上,離1最接近的地址是8了,所以d被放在了8,此時下一個空閒地址變成了
16,下一個元素c的對界是4,16可以滿足,所以c放在了16,此時下一個空閒地址變成了20,下一
個元素d需要對界1,也正好落在對界上,所以d放在了20,結構體在地址21處結束。由於s1的大小
需要是8的倍數,所以21-23的空間被保留,s1的大小變成了24。
對於s2,首先把a放到8的對界,假定是0,此時下一個空閒地址是1,下一個元素的對界也是1,所
以b擺放在1,下一個空閒地址變成了2;下一個元素c的對界是4,所以取離2最近的地址4擺放c,
下一個空閒地址變成了8,下一個元素d的對界是8,所以d擺放在8,所有元素擺放完畢,結構體在
15處結束,佔用總空間為16,正好是8的倍數。

這裡有個陷阱,對於結構體中的結構體成員,不要認為它的對齊方式就是他的大小,看下面的例子:


struct s1
{
 char a[8];
};
struct s2
{
 double d;
};
struct s3
{
 s1 s;
 char a;
};
struct s4
{
 s2 s;
 char a;
};


s1和s2大小雖然都是8,但是s1的對齊方式是1,s2是8(double),所以在s3和s4中才有這樣的差異。

所以,在自己定義結構體的時候,如果空間緊張的話,最好考慮對齊因素來排列結構體裡的元素。


10、不要讓double干擾你的位域


在結構體和類中,可以使用位域來規定某個成員所能佔用的空間,所以使用位域能在一定程度上節
省結構體佔用的空間。不過考慮下面的程式碼:


struct s1
{
 int i: 8;
 int j: 4;
 double b;
 int a:3;
};

struct s2
{
 int i;
 int j;
 double b;
 int a;
};
struct s3
{
 int i;
 int j;
 int a;
 double b;
};
struct s4
{
 int i: 8;
 int j: 4;
 int a:3;
 double b;
};


可以看到,有double存在會干涉到位域(sizeof的演算法參考上一節),所以使用位域的的時候,最好
把float型別和double型別放在程式的開始或者最後。

第一次寫東西,發現自己的表達能力太差了,知道的東西講不出來,講出來的東西別人也看不懂,呵呵
。另外,C99標準的sizeof已經可以工作在執行時了,打算最近找個支援C99的編譯器研究一下。


首先拉來看個例子:

struct test
{
char a;
int b;
};
int main()
{
int nSize = sizeof(test);
  return 0;
}

在使用vc編譯器預設設定下得到的nsize是8,而不是5.為什麼要這樣呢?

原來在cpu定址是是8的倍數的地址是最容易找到的,所以在vc預設編譯情況下,都會把結構體按8位元組對齊,這樣就可以提高了編譯出來效率。

vc在project->setting->c/c++中的struct member alignment中可以設定結構體補齊方式,預設情況下是8,如果改成1的話,上面的sizeof得到的結果就是5了。

那麼現在我們還是用預設的8位元組方式,把int b改成short b,得到的結果是多少呢?哈,是4.

原來struct的對齊機制裡面還有另外一個規則就是首先計算結構體內所有基礎型別的長度,最大的長度如果小於vc設定的對齊長度的話,就按最大長度作為結構體的對齊方式。如上面改成short以後,結構體內最大對齊長度是2(short),所以最終的結構體是按2位元組來補齊的,而不是預設的8位元組。


typedef  struct  tagSocketData  { 
   BYTE          nSize; 
   BYTE          nType; 
   DWORD        nDataSize; 
   DWORD        nIndex; 
   SOCKET      socket; 
   DWORD        nDataLength; 
}  SOCKETDATA,  *LPSOCKETDATA; 
 
SOCKETDATA  sd; 
sd.nSize  =  sizeof(SOCKETDATA);    //本來應該是18,  可卻是20 
 
sizeof(SOCKETDATA)  =  20,  本來是18位元組的大小 
實際大小卻是20 
可存為檔案的時候卻是按照18位元組的大小儲存

相關推薦

13)結構問題

ngs dmi nts min mage ++ image http c語言 詳細可以看 臺式機的 C:\Documents and Settings\Administrator\桌面\C++基礎教程完整版視頻\01_C語言提高\d

結構

str center 但是 內存 read 地址 形式參數 class area 1 C語言裏可以在一個存儲區裏記錄多個相關數字這種存儲區的類型叫結構體類型,這種類型需要首先創建出來然後才能使用 2 結構體類型存儲區裏包含多個子存儲區,每個子存儲區可以記錄一個數字,結構體中

linux中結構【轉】

src double 無需 fine types 查看 真理 blog 多個 轉自:https://blog.csdn.net/suifengpiao_2011/article/details/47260085 linux中定義對齊字節 typedef struct

逆向基礎之結構

eof 成員對齊 偏移 str 最大 結構體 基礎 數據 sizeof 遵循以下原則,數據成員對齊;結構體大小;結構體有某些成員大,最大對齊,對齊參數筆結構體的sizeof小,偏移以此為準。struct{ char a;int b;char c;}a 1b,補3b 4bc

結構總結

結構體對齊 結構體對齊到底是什麼,看了網上很多的解答,彙總成個人經驗 什麼是結構體對齊 結構體對齊規則 考慮一個問題,為什麼要設計記憶體對齊的處理方式呢? ENDING 結構體對齊到底是什麼,看了網上很多

C語言結構(記憶體問題)

C語言結構體對齊也是老生常談的話題了。基本上是面試題的必考題。內容雖然很基礎,但一不小心就會弄錯。寫出一個struct,然後sizeof,你會不會經常對結果感到奇怪?sizeof的結果往往都比你宣告的變數總長度要大,這是怎麼回事呢?     開始學的時候,

結構——結構記憶體佈局

在C語言中,可以通過#pragma pack(n)來指定結構體按n位元組對齊(這裡的n是2的較小整數次冪)。如果程式設計者不指定對齊位元組數,那麼預設的會按照結構體中最長那一項對齊,如在64位作業系統中,當結構體中出現(void *),(long)型別,則必然是按照8位元組對齊;當最大的是int,那麼就按照4

結構——結構體內存布局

聲明 amp pri 最大的 結構 sdn int spa turn 在C語言中,可以通過#pragma pack(n)來指定結構體按n字節對齊(這裏的n是2的較小整數次冪)。如果程序設計者不指定對齊字節數,那麽默認的會按照結構體中最長那一項對齊,如在64位操作系統中,當結

C/C++結構方式詳解,從記憶體地址進行解析

注意:童鞋們如果仔仔細細看完這篇部落格,肯定能明白結構體的對齊方式。 最近在做一個專案的時候,客戶給的鐳射點雲檔案是二進位制形式,因此需要根據客戶定義的結構體,將點雲檔案儲存為文字檔案方便在第三方軟體如cloudCompare中檢視。但是發現客戶的結構體所佔記憶體空間跟我的

sizeof與strlen用法詳解(結構)

#include<stdio.h> int main(int argc,char **argv) { unsigned char a[10] ={1,2,1,2,3,4}; unsigned char a1[10] ={0,0,0,0,0,0}; char *

C-結構

技術群的筒子們有時候會提到結構體對齊,說實話這個問題還不是幾句話能講清楚的。這個問題網上一搜一大把,已經有無數的前輩總結過。看了很多網上的資料,根據我個人的一些理解,再總結一下,配了些圖片,希望大家能看懂。 首先是結構體對齊規則: 1、對於n個位元組的元素,它的首地址要能

c結構深刻理解

1. 先看下面的例子: struct A{    char c1;    int i;    short s;    int j; }a; struct B{    int i;    int j;      short s;    char c1; }b; 結構A沒有遵守位元組對齊原則(為了區分,我將它叫做

C++關於結構

說明: 結構體的sizeof值,並不是簡單的將其中各元素所佔位元組相加,而是要考慮到儲存空間的位元組對齊問題。這些問題在平時程式設計的時候也確實不怎麼用到,但在一些筆試面試題目中出是常常出現,一、解釋 現代計算機中記憶體空間都是按照byte劃分的,從理論上講

結構問題.

Intel、微軟等公司曾經出過一道類似的面試題: 2.1 自然對界   struct是一種複合資料型別,其構成元素既可以是基本資料型別(如int、long、float等)的變數,也可以是一些複合資料型別(如array、struct、union等)的資料單元。對於結構體,編譯器會自動進行成員變數的對齊,以提高

c++結構

參考各資料得出自己使用的公式:1、(當前偏移量+當前填充數)%當前變數大小=02、(總偏移大小+末尾填充數)%最寬變數大小=0必須先滿足1、再滿足2。例如程式碼如下:struct A{int a;//(當前偏移量0+當前填充數0)%當前變數大小4=0char b;// (當前

結構的原則及原因分析

為什麼要對齊?     現代計算機中記憶體空間都是按照byte劃分的,從理論上講似乎對任何型別的變數的訪問可以從任何地址開始,但實際情況是在訪問特定型別變數的時候經常在特 定的記憶體地址訪問,這就需要各種型別資料按照一定的規則在空間上排列,而不是順序的一個接一個的排放,

64位系統結構訪問段錯誤

先放程式碼: #include struct s { char c; int b; }; int main(void){ printf("sizeof (struct s) = %d.\n

C語言結構與不對設定總結

相信不同的編譯平臺間的預設設定差異給大家帶來了很多困擾。在此,僅就結構體對齊解析下之間的差異設定方法。 1.gcc中結構體預設是4個位元組對齊,即為32的倍數。 1.1修改位元組對齊: struct data{ int a; char b; char c; }__

C/C++結構_思索

       最近在看對齊方面的問題,發現大家在面試筆試的時候,對方基本上都是會拿包含陣列的結構體、或者包含結構體的結構體來考大家,而不會單純的拿幾個int,long,或者double組合在一起考,因為那樣太簡單,找了些資料,幫助自己也幫助大家理解下,共同交流!      

結構問題以及強制型別轉換問題總結

一、什麼是對齊     現在使用的計算機中記憶體空間都是按照位元組劃分的,從理論上講似乎對任何型別的變數的訪問都可以從任何地址開始,但實際上計算機系統對於基本資料型別在記憶體中的存放位置都有限制。舉個例子,一個變數佔用n個位元組,則該變數的起始地址必須能夠被n整除,即存放