首先,看下題。
#include
#include#include"head.h"
#pragma pack(8)
using namespace std;
struct abcd
;struct cabd
;int main()
{ cout<
結果: 16
24 要能清除的分析上面的問題就要搞清楚結構體變數的成員在記憶體裡是如何分布的、成員先後順序是怎樣的、成員之間是連續的還是分散的、還是其他的什麼形式?其實這些問題既和軟體相關又和硬體相關。所謂軟體相關主要是指和具體的程式語言的編譯器的特性相關,編譯器為了優化cpu訪問記憶體的效率,在生成結構體成員的起始位址時遵循著某種特定的規則,這就是所謂的結構體成員「對齊」;所謂硬體相關主要是指cpu的「位元組序」問題,也就是大於乙個位元組型別的資料如int型別、short型別等,在記憶體中的存放順序,即單個位元組與高低位址的對應關係。位元組序分為兩類:big-endian和little-endian,有的文章上稱之為「大端」和「小端」,他們是這樣定義的:
little-endian就是低位位元組排放在記憶體的低位址端,高位位元組排放在記憶體的高位址端;big-endian就是高位位元組排放在記憶體的低位址端,低位位元組排放在記憶體的高位址端。
為了優化cpu訪問記憶體的效率,程式語言的編譯器在做變數的儲存分配時就進行了分配優化處理,優化規則大致原則是這樣:對於n位元組的元素(n=2,4,8,...),它的首位址能被n整除,這種原則稱為「對齊」,如word(2位元組)的值應該能被2整除的位置,dword(4位元組)應該在能被4整除的位置。對於結構體來說,結構體的成員在記憶體中順序存放,所佔記憶體位址依次增高,第乙個成員處於低 位址處,最後乙個成員處於最高位址處,但結構體成員的記憶體分配不一定是連續的,編譯器會對其成員變數依據前面介紹的 「對齊」原則進行處理。對待每個成員類似於對待單個n位元組的元素一樣,依次為每個元素找乙個適合的首位址,使得其符合上述的「對齊」原則。
通常編譯器中可以設定乙個對齊引數n,但這個n並不是結構體成員實際的對齊引數,vc++6.0中結構體的每個成員實際對齊引數n通常是這樣計算得到的
n=min(sizeof(該成員型別),n)(n為vc++6.0中可設定的值)。
成員的記憶體分配規律是這樣的:從結構體的首位址開始向後依次為每個成員尋找第乙個滿足條件的首位址x,該條件是x % n = 0,並且整個結構的長度必須為各個成員所使用的對齊引數中最大的那個值的最小整數倍,不夠就補空位元組。
結構體中所有成員的對齊引數n的最大值稱為結構體的對齊引數。
gcc編譯器中預設的n值為8,可以通過程式進行控制,如
#pragma pack(n) ,n=1,2,4,8,12.其他的引數是無效的。
回過頭來看上面的題目,
#pragma pack(8)沒有修改預設值,因此,對齊引數仍為8。
struct abcd結構體,
int a,佔4位元組,n=4,0%4=0,
偏移位址為0,
位址為[0-3];
char b,佔1位元組,n=1,4%4=0,偏移位址為4,位址為[4];
short c,佔2位元組,n=2,6%2=0,偏移位址為6,位址為[6-7];前面補一位
double d,佔8位元組,n=8,8%8=0,偏移位址為8,位址為[8-15];
整個結構體的n=8,結構體長度為16位元組。
struct cabd結構體,
short c,佔2位元組,n=2,0%2=0,偏移位址為0,位址為[0-1];
int a,佔4位元組,n=4,4%4=0,偏移位址為4,位址為[4-7];前面補2位
char b,佔1位元組,n=1,8%1=0,偏移位址為8,位址為[8];
double d,佔8位元組,n=8,16%8=0,偏移位址為16,位址為[16-23];前面補7位
整個結構體的n=8,結構體長度為24.
一、記憶體對齊的原因
大部分的參考資料都是如是說的:
1、平台原因(移植原因):不是所有的硬體平台都能訪問任意位址上的任意資料的;某些硬體平台只能在某些位址處取某些特定型別的資料,否則丟擲硬體異常。
2、效能原因:資料結構(尤其是棧)應該盡可能地在自然邊界上對齊。原因在於,為了訪問未對齊的記憶體,處理器需要作兩次記憶體訪問;而對齊的記憶體訪問僅需要一次訪問。
二、對齊規則
每個特定平台上的編譯器都有自己的預設「對齊係數」(也叫對齊模數)。程式設計師可以通過預編譯命令#pragma pack(n),n=1,2,4,8,16來改變這一係數,其中的n就是你要指定的「對齊係數」。 對齊步驟:
1、資料成員對齊規則:結構(struct)(或聯合(union))的資料成員,第乙個資料成員放在offset為0的地方,以後每個資料成員的對齊按照#pragma pack指定的數值和這個資料成員自身長度中,比較小的那個進行。
2、結構(或聯合)的整體對齊規則:在資料成員完成各自對齊之後,結構(或聯合)本身也要進行對齊,對齊將按照#pragma pack指定的數值和結構(或聯合)最大資料成員長度中,比較小的那個進行。
3、結合1、2顆推斷:當#pragma pack的n值等於或超過所有資料成員長度的時候,這個n值的大小將不產生任何效果。
備註:陣列成員按長度按陣列型別長度計算,如char t[9],在第1步中資料自身長度按1算,累加結構體時長度為9;第2步中,找最大資料長度時,如果結構體t有複雜型別成員a的,該a成員的長度為該複雜型別成員a的最大成員長度。
關於結構體,記憶體對齊,sizeof
程式設計師寶典中,關於結構體對齊問題,看了一晚上帖子,包括記憶體,cpu等等的,現在總算有些理解 要弄清結構體對齊,首先要明白為什麼要對齊?1.先想想簡單的hello.c整個執行過程中外設,記憶體,cpu的工作過程 計算機的所有工作都是要經過記憶體的,包括網頁得讀取等等 我們平時說的32位機器是指指...
《複習》指標結構體內存分配
一.指標 指標的重要性 指標是c語言的靈魂 定義位址 記憶體單元的編號 從0開始的非負整數 範圍 0 ffffffff 指標指標就是位址,位址就是指標 指標變數是存放在記憶體單元位址的變數 指標的本質是乙個操作受限的非負整數 分類1.基本型別的指標 p i p和i等價 修改 p和i都能改變記憶體上儲...
結構體內存分配 舉例待續
定義結構體型別,系統不為之分配記憶體單元。當使用結構體型別定義變數時,才開闢記憶體單元。結構體在記憶體中所佔的大小決定於兩點 1.編譯器預設或指定對齊數 eg 64為ubuntu14.04 預設8 這個可通過 pragma pack n 來指定 2.每個成員 實際有效對齊數,指的是所有成員中所佔位元...