sizeof struct 的結果分析及其原因

2021-08-19 17:57:13 字數 3477 閱讀 3468

有的時候,在腦海中停頓了很久的「顯而易見」的東西,其實根本上就是錯誤的。就拿下面的問題來看:

struct t

; 使用sizeof(t),將得到什麼樣的答案呢?要是以前,想都不用想,在32位機中,int是4個位元組,char是1個位元組,所以t一共是5個位元組。實踐出真知,在vc6中測試了下,答案確實8個位元組。哎,反正受傷的總是我,我已經有點麻木了,還是老老實實的接受吧!為什麼答案和自己想象的有出入呢?這裡將引入記憶體對齊這個概念。

二 記憶體對齊概念及其提出的原因

許多計算機系統對其內建型別的存放位置有一定的限制,通常會按照一定的倍數k存放相應的型別,這種方式即為記憶體對齊。其中k稱為記憶體模數。

def:若sizeof(struct s1)/sizeof(struct s2)>1 則稱s1的對齊要比s2的對齊嚴格,反之相反。

為什麼要提出記憶體對齊?

比如這麼一種處理器,它每次讀寫記憶體的時候都從某個8倍數的位址開始,一次讀出或寫入8個位元組的資料,假如軟體能保證double型別的資料都從8倍數字址開始,那麼讀或寫乙個double型別資料就只需要一次記憶體操作。否則,我們就可能需要兩次記憶體操作才能完成這個動作,因為資料或許恰好橫跨在兩個符合對齊要求的8位元組記憶體塊上。(在有謝處理器上記憶體不對齊的話可能會出現錯誤)

三 一些例子(在vc的編譯器上)

下面用前面的例子來說明vc到底怎麼樣來存放結構的。

struct mystruct

double dda1;

char dda;

int type

為上面的結構分配空間的時候,vc根據成員變數出現的順序和對齊方式,先為第乙個成員dda1分配空間,其起始位址跟結構的起始位址相同(剛好偏移量0剛好為sizeof(double)的倍數),該成員變數占用sizeof(double)=8個位元組;接下來為第二個成員dda分配空間,這時下乙個可以分配的位址對於結構的起始位址的偏移量為8,是sizeof(char)的倍數,所以把dda存放在偏移量為8的地方滿足對齊方式,該成員變數占用sizeof(char)=1個位元組;接下來為第三個成員type分配空間,這時下乙個可以分配的位址對於結構的起始位址的偏移量為9,不是sizeof(int)=4的倍數,為了滿足對齊方式對偏移量的約束問題,vc自動填充3個位元組(這三個位元組沒有放什麼東西),這時下乙個可以分配的位址對於結構的起始位址的偏移量為12,剛好是sizeof(int)=4的倍數,所以把type存放在偏移量為12的地方,該成員變數占用sizeof(int)=4個位元組;這時整個結構的成員變數已經都分配了空間,總的占用的空間大小為:8+1+3+4=16,剛好為結構的位元組邊界數(即結構中占用最大空間的型別所占用的位元組數sizeof(double)=8)的倍數,所以沒有空缺的位元組需要填充。所以整個結構的大小為:sizeof(mystruct)=8+1+3+4=16,其中有3個位元組是vc自動填充的,沒有放任何有意義的東西。

面再舉個例子,交換一下上面的mystruct的成員變數的位置,使它變成下面的情況:

struct mystruct

char dda;

double dda1;

int type

這個結構占用的空間為多大呢?在vc6.0環境下,可以得到sizeof(mystruc)為24。結合上面提到的分配空間的一些原則,分析下vc怎麼樣為上面的結構分配空間的。(簡單說明)

struct mystruct

char dda;//偏移量為0,滿足對齊方式,dda占用1個位元組;

//的倍數,需 要補足7個位元組才能使偏移量變為8(滿足對齊

//方式),因 此vc自動填充7個位元組,dda1存放在偏移量為8

//的位址上, 它占用8個位元組。

//數,滿足int的對齊方式,所以不需要vc自動填充,type存

//放在偏移量為16的位址上,它占用4個位元組。

};//所有成員變數都分配了空間,空間總的大小為1+7+8+4=20,不是結構

//的節邊界數(即結構中占用最大空間的型別所占用的位元組數sizeof

//(double)=8)的倍數,所以需要填充4個位元組,以滿足結構的大小為

//sizeof(double)=8的倍數。

所以該結構總的大小為:sizeof(mystruc)為1+7+8+4+4=24。其中總的有7+4=11個位元組是vc自動填充的,沒有放任何有意義的東西。

vc對結構的儲存的特殊處理確實提高cpu儲存變數的速度,但是有時候也帶來了一些麻煩,我們也遮蔽掉變數預設的對齊方式,自己可以設定變數的對齊方式。

vc中提供了#pragma pack(n)來設定變數以n位元組對齊方式。n位元組對齊就是說變數存放的起始位址的偏移量有兩種情況:第

一、如果n大於等於該變數所占用的位元組數,那麼偏移量必須滿足預設的對齊方式,第

二、如果n小於該變數的型別所占用的位元組數,那麼偏移量為n的倍數,不用滿足預設的對齊方式。結構的總大小也有個約束條件,分下面兩種情況:如果n大於所有成員變數型別所占用的位元組數,那麼結構的總大小必須為占用空間最大的變數占用的空間數的倍數;

否則必須為n的倍數。下面舉例說明其用法。

struct test

char m1;

double m4;

int m3;

以上結構的大小為16,下面分析其儲存情況,首先為m1分配空間,其偏移量為0,滿足我們自己設定的對齊方式(4位元組對齊),m1占用1個位元組。接著開始為m4分配空間,這時其偏移量為1,需要補足3個位元組,這樣使偏移量滿足為n=4的倍數(因為sizeof(double)大於n),m4占用8個位元組。接著為m3分配空間,這時其偏移量為12,滿足為4的倍數,m3占用4個位元組。這時已經為所有成員變數分配了空間,共分配了16個位元組,滿足為n的倍數。如果把上面的#pragma pack(4)改為#pragma pack(16),那麼我們可以得到結構的大小為24。(請讀者自己分析)

2、 sizeof用法總結

在vc中,sizeof有著許多的用法,而且很容易引起一些錯誤。下面根據sizeof後面的引數對sizeof的用法做個總結。

a.引數為資料型別或者為一般變數。例如sizeof(int),sizeof(long)等等。這種情況要注意的是不同系統系統或者不同編譯器得到的結果可能是不同的。例如int型別在16位系統中佔2個位元組,在32位系統中佔4個位元組。

b.引數為陣列或指標。下面舉例說明.

int a[50]; //sizeof(a)=4*50=200;求陣列所佔的空間大小

int *a=new int[50];// sizeof(a)=4; a為乙個指標,sizeof(a)是求指標

//的大小,在32位系統中,當然是佔4個位元組。

c.引數為結構或類。sizeof應用在類和結構的處理情況是相同的。但有兩點需要注意,第

一、結構或者類中的靜態成員不對結構或者類的大小產生影響,因為靜態變數的儲存位置與結構或者類的例項位址無關。

第二、沒有成員變數的結構或類的大小為1,因為必須保證結構或類的每一

個例項在記憶體中都有唯一的位址。

下面舉例說明,

class test;//sizeof(test)=4.

test *s;//sizeof(s)=4,s為乙個指標。

class test1;//sizeof(test1)=1;

sizeof struct 大小討論

2009 11 08 14 05 51 分類 c語言雜記 舉報 字型大小 訂閱 struct 結構大小和順序 progma pack引數有關係 針對位元組對齊,環境使用的gcc version 3.2.2編譯器 32位x86平台 為例。char 長度為1個位元組,short 長度為2個位元組,int...

sizeof struct 大小討論

struct 結構大小和順序 progma pack引數有關係 針對位元組對齊,環境使用的 gcc version 3.2.2 編譯器 32位 x86平台 為例。char 長度為1個位元組,short 長度為2個位元組,int 長度為4個位元組。struct 子項在記憶體中的按順序排列,在沒有 pr...

sizeof(struct)對齊方式

結構體是一種復合資料型別,通常編譯器會自動的進行其成員變數的對齊,已提高資料訪問的效率。在預設情況下,編譯器為結構體的成員按照自然對齊 natural alignment 條方式分配儲存空間,各個成員按照其宣告順序在儲存器中順序儲存。自然對齊是指按照結構體中成員size最大的對齊,在cl編譯器下可以...