① c語言結構體變數的大小問題
還要考慮編譯器優化的內存對齊
C語言標准本身沒有要求結構體/聯合體的成員間內存存儲需要連續
編譯器為了高效存取數據,犧牲部分內存空間,提高存取的效率
② c語言結構體的問題,存儲空間大小
win32
4位元組對齊
變數內存的起始地址的邊界是跟它類型一致的
比如int類型,可以認為它存在4的倍數的地址,short存在2位元組倍數開始的地址,char存在1位元組開始的地址,即任意地址
因此,回過頭來看
第一個結構
假設int
a;///4位元組倍數地
short
b;//推理a的末尾是4位元組倍數地址也是2位元組倍數地址,所以b是挨著a存的
char
c;//任意其實地址,挨著b存放
看起來7個位元組就放下了,但是需要兼顧4位元組對齊的原則,在末尾補了一個位元組
第二個結構也類似
結構體與普通類型並無大區別,存儲區域也一樣的
③ 結構體類型的長度計算
計算方法:
運算符sizeof可以計算出給定類型的大小,對於32位系統來說,sizeof(char)
=
1;
sizeof(int)
=
4。基本數據類型的大小很好計算,我們來看一下如何計算構造數據類型的大小。
c語言中的構造數據類型有三種:數組、結構體和共用體。
數組是相同類型的元素的集合,只要會計算單個元素的大小,整個數組所佔空間等於基礎元素大小乘上元素的個數。
結構體中的成員可以是不同的數據類型,成員按照定義時的順序依次存儲在連續的內存空間。和數組不一樣的是,結構體的大小不是所有成員大小簡單的相加,需要考慮到系統在存儲結構體變數時的地址對齊問題。看下面這樣的一個結構體:
struct
stu1
{
int
i;
char
c;
int
j;
};
先介紹一個相關的概念——偏移量。偏移量指的是結構體變數中成員的地址和結構體變數地址的差。結構體大小等於最後一個成員的偏移量加上最後一個成員的大小。顯然,結構體變數中第一個成員的地址就是結構體變數的首地址。因此,第一個成員i的偏移量為0。第二個成員c的偏移量是第一個成員的偏移量加上第一個成員的大小(0+4),其值為4;第三個成員j的偏移量是第二個成員的偏移量加上第二個成員的大小(4+1),其值為5。
實際上,由於存儲變數時地址對齊的要求,編譯器在編譯程序時會遵循兩條原則:一、結構體變數中成員的偏移量必須是成員大小的整數倍(0被認為是任何數的整數倍)
二、結構體大小必須是所有成員大小的整數倍。
對照第一條,上面的例子中前兩個成員的偏移量都滿足要求,但第三個成員的偏移量為5,並不是自身(int)大小的整數倍。編譯器在處理時會在第二個成員後面補上3個空位元組,使得第三個成員的偏移量變成8。
對照第二條,結構體大小等於最後一個成員的偏移量加上其大小,上面的例子中計算出來的大小為12,滿足要求。
再看一個滿足第一條,不滿足第二條的情況
struct
stu2
{
int
k;
short
t;
};
成員k的偏移量為0;成員t的偏移量為4,都不需要調整。但計算出來的大小為6,顯然不是成員k大小的整數倍。因此,編譯器會在成員t後面補上2個位元組,使得結構體的大小變成8從而滿足第二個要求。由此可見,大家在定義結構體類型時需要考慮到位元組對齊的情況,不同的順序會影響到結構體的大小。對比下面兩種定義順序
struct
stu3
{
char
c1;
int
i;
char
c2;
}
struct
stu4
{
char
c1;
char
c2;
int
i;
}
雖然結構體stu3和stu4中成員都一樣,但sizeof(struct
stu3)的值為12而sizeof(struct
stu4)的值為8。
如果結構體中的成員又是另外一種結構體類型時應該怎麼計算呢?只需把其展開即可。但有一點需要注意,展開後的結構體的第一個成員的偏移量應當是被展開的結構體中最大的成員的整數倍。看下面的例子:
struct
stu5
{
short
i;
struct
{
char
c;
int
j;
}
ss;
int
k;
}
結構體stu5的成員ss.c的偏移量應該是4,而不是2。整個結構體大小應該是16。
如何給結構體變數分配空間由編譯器決定,以上情況針對的是linux下的gcc。其他平台的c編譯器可能會有不同的處理。
④ C語言中結構體位元組的計算方式
在說計算方式之前先講講幾個概念一個是 偏移量 還有一個是 內存對齊 。先說偏移量,網路對於它的定義是這樣:把存儲單元的實際地址與其所在段的段地址之間的距離稱為段內偏移,也稱為「有效地址或偏移量」。在結構體裡面大概是指結構體變數中成員的地址和結構體變數地址的差。然後再說一下內存對齊這個概念:內存中存放基本類型數據時,計算機的系統會對其位置有限制,系統會要求這些數據的首地址的值是某個數的倍數,而這個數被稱為該數據類型的對齊模數。雖然ANSI C標准中沒有強制規定相鄰聲明的變數內存中要相鄰,但是編譯器會自動幫你處理這個問題,也就是相鄰變數之間可能會填充一些位元組。因此在這個問題上又有了編譯器的區別。
那我們先來講講結構體變數在微軟的編譯器的對齊吧
1.結構成員的首地址要是其最寬的基本類型成員的整數倍。編譯器在給結構體分配內存的時候先找到最寬的基本成員,然後再在內存中尋找地址,並將這個最寬的基本數據類型的大小作為對齊模數
2.結構體每一個成員相對於首地址的偏移量是成員大小的整數倍,如果沒有達到這個要求,編譯器會自動填加位元組。編譯器在為結構體成員開辟內存的時候會先檢查開辟內存的首地址與結構體變數的首地址之間的偏移量,如果是成員體的整數倍那麼就存放這個變數,不然的話就在這個成員和上一個成員之間填充位元組,以達到整數倍的目的
3.結構體所佔的總內存大小要是最大成員體大小的整數倍,如果不是,那麼編譯器會在末尾補充位元組。結構體的最後一個成員,不僅要滿足前兩條原則,最後一條准則也要滿足。
接下來來看看幾個例子。
這個結構體在VS 2017下的sizeof的運算結果是12。那麼根據上面的對其規則我們來對其進行計算。
首先是char a。char大小是1,相對於首地址的偏移量是0,然後是int i。int i的大小是4,相對於首地址的偏移量是1,但是1不是4的整數倍,所以編譯器會自動在char a和int i之間填充位元組位元組。所以in i的偏移量是4。而之後的float b大小4偏移量就是int i的偏移量加上int i的大小故float b的偏移量大小就是8,而8正好是4的倍數那麼就不會有位元組填充。而結構體的大小也就自然是最後8+4=12了
從這里也可以看出結構體大小等於最後一個成員體的大小加上它的偏移量。
那麼我們再來看一個例子
那麼我們再利用之前的演算法來對其進行運算,int i的大小是4偏移量是0,int c 的大小是4偏移量是4,double b的大小是8,偏移量是8。char a的大小是1 ,偏移量是16。那麼這個結構體的變數的大小就是16+1=17嗎?答案肯定不是這樣的。在VS的sizeof的運算下這個的結果是24,為什是24呢,那麼這之前說的最後一條原則就要用上了。結構體的大小確實是等於最後一個成員的偏移量加上最後一個成員的大小,但是如果這個結構不滿足是結構體中最大成員大小的整數倍這個條件那麼,編譯器會自動在最後填充位元組使其滿足,也就是說,雖然我們計算出的結果是17但是17並不是8的倍數,所以編譯器自動在最後填充位元組使其成為8的倍數,即自動擴充成24.、
那我們再來說一下GCC編譯器下的模式。GCC編譯器在Windows環境下用的會比較少,主要在Linux平台下使用GCC編譯器就不遵守微軟的編譯器下的一些准則了,比如之前 說過的對齊模數。微軟的編譯器下的對齊模數是結構體成員中最大的大小而在GCC編譯器下對齊模數最大隻能是4。這就意味著對齊模數只能是1,2,4中的一個。因此之前講過的在微軟編譯器下的的一些原則會有些不同。之前講過的成員的首地址的偏移量要是成員大小的整數倍在這里就有點區別了。在GCC中如果成員大小小於等數4那麼繼續按照之前的標准就好了,但如果大於4,則結構體每個成員相對於結構體首地址的偏移量只能按照是4的整數倍來進行判斷是否添加填充。來看一個簡單的例子。
在這個例子中,如果是按照微軟的編譯器的話計算的結構應該是16,但是在GCC編譯器下是12。道理就是之前講的。
雖然理論上如此但是我自己在試的時候發現上面的運算結果是16,沒錯是16而不是12!為什麼呢?難道是這個理論錯了么,當然不是。我們可以嘗試在GCC下計算一下sizeof(int *)(是int *而不是int)。你會發現結果是8(如果是sizeof(int)那麼結果結果就是4),輸出結果是8那就解決了我們的疑惑。 64位系統的對其長度默認是8而32位的才是4 。這就合理解釋了為什麼計算結果是16而不是12。
對齊模數的選擇只能是基於基本數據類型,所以對於結構體嵌套結構體就不能這么,至於其的計算方式之後再補充
⑤ C語言求結構體sizeof怎麼求
sizeof()用來測給定的數據類型在內存中占的位元組長度;
比如我想知道int類型變數占幾個位元組 就這樣使用:len = sizeof(int) 就可以了,len就是int型變數在內存中位元組數;
當然你也可以這么用 int a; len = sizeof(a); 編譯器會知道a是int型變數的,會自動換成sizeof(int);
另外 自己定義的數據類型也可以用sizeof來求位元組數,比如定義了一個類class A{...},然後你
這樣用:len = sizeof(A),就能知道A佔了幾個位元組;
最後,提示下,sizeof是關鍵字或者說是運算符,不是函數,它的結果是編譯的時候就確定了的,沒有函數調用;
⑥ C語言結構體及長度問題
a四位元組對齊,所以應該是16
b是指針,就是4個位元組
你那個答案是16位機器,現在上哪找去。。