記憶體對齊和位域

2021-08-04 01:21:23 字數 2978 閱讀 5491

結構體的記憶體結構

當我們解決實際問題時,我們會發現編譯器提供給我們的內建型別其實不夠用,沒有辦法用同一種型別儲存多種型別的資料,c語言中有自己的自定義型別,比如結構、位域、聯合、列舉、typedef關鍵字等。下面我就簡單的介紹一下結構和位域。

結構:在乙個名字下的一組變數,有時也稱為聚集資料型別。

位域:這是結構的一種變形,允許對字中的位進行訪問。

當我們申請乙個結構體時,它會佔多少個位元組呢?我們來看一段**:

#include

using namespace std;

int main()

;struct b ;

struct c ;

cout << sizeof(a) << endl;

cout << sizeof(b) << endl;

cout << sizeof(c) << endl;

return 0;

}輸出的結果為:123

12如圖:

補2就是為了方便最後乙個int型別便於訪問,可以只訪問一次,struct c的對齊模數為4。

前兩個結構體的答案大家可以理解,但為什麼第三個結構的答案會是這樣呢?原來是因為記憶體對齊,那麼為什麼編譯器會有記憶體對齊呢?

2. 效能原因:資料結構(尤其是棧)應該盡可能地在自然邊界上對齊。因為為了訪問未對齊的記憶體,處理器需要做兩次記憶體訪問,而對齊的記憶體僅需要一次訪問。

許多計算機系統對基本型別資料在記憶體中存放的位置有限制,它們會要求這些資料的首位址的值是某個值k(通常為4或8)的倍數,這就是所謂的記憶體對齊,這個k就是對齊模數。

記憶體對齊的規定:

1.資料成員對齊規則:結構(struct或聯合union)的資料成員,第乙個資料成員放在offset為0的地方,以後每個資料成員儲存的起始位置要從該成員自身大小的整數倍開始(比如int在32位機為4位元組,則要從4的整數倍位址開始儲存)。

編譯器在給結構體開闢空間時,首先找到結構體中最寬的基本資料型別,然後尋找記憶體位址能被該基本資料型別所整除的位置,作為結構體的首位址。將這個最寬的基本資料型別的大小作為上面介紹的對齊數。

2.結構體作為成員:如果乙個結構裡有某些結構體成員,則結構體成員要從其內部最大元素大小的整數倍位址開始儲存。(struct a裡存有struct b,b裡有char,int,double等元素,那b應該從8的整數倍開始儲存。)

為結構體的乙個成員開闢空間之前,編譯器首先檢查預開闢空間的首位址相對於結構體首位址的偏移是否是本成員的整數倍,若是,則存放本成員,反之,則在本成員和上乙個成員之間填充一定的位元組,以達到整數倍的要求,也就是將預開闢空間的首位址後移幾個位元組。

3.結構體成員相對首位址偏移量必須是成員大小的整數倍,也就是記憶體對齊。

4.結構體總大小必須是對齊模數的整數倍,舉個例子,你最後加出來的值為30,但是你得對齊模數是8,這時候你就要補充兩個位元組,讓結構體大小為32

5.結構體的對齊模數其實還是自定義的,具體格式為

#pragma back(需要的對其模數)

接下來再看乙個例子

#include

using namespace std;

int main()

;struct b ;

cout << sizeof(a) << endl;

cout << sizeof(b) << endl;

return 0;

}結果為:

2440

我們再來畫一下它的儲存情況

位域(乙個位元組有八位)

有些資訊在儲存時,並不需要占用乙個完整的位元組, 而只需佔幾個或乙個二進位制位。例如在存放乙個開關量時,只有0和1 兩種狀態, 用一位二進位即可。為了節省儲存空間,並使處理簡便,c語言又提供了一種資料結構,稱為「位域」或「位段」。所謂「位域」是把乙個位元組中的二進位劃分為幾個不同的區域,並說明每個區域的位數。每個域有乙個網域名稱,允許在程式中按網域名稱進行操作。這樣就可以把幾個不同的物件用乙個位元組的二進位制位域來表示。一、位域的定義和位域變數的說明位域定義與結構定義相仿,其形式為:struct 位域結構名

;其中位域列表的形式為: 型別說明符 位網域名稱:位域長度

位域的儲存要求:

struct bs

;cout << sizeof(bs);

結果為2

2.由於位域不允許跨兩個位元組,因此位域的長度不能大於乙個位元組的長度,也就是說不能超過8位二進位。

3.位域可以無位網域名稱,這時它只用來作填充或調整位置。無名的位域是不能使用的。例如:

struct k

;結果為2

位域的使用:

位域的使用和結構成員的使用相同,其一般形式為:

「位域變數名·位網域名稱」位域允許用各種格式輸出。

struct k

kk, *ko;

kk.a = 2; kk.b = 6; kk.c = 5;

cout << kk.a << " " << kk.b << " " << kk.c << endl;

ko = &kk;

ko->a=1;

ko->b&=3;//ko->b&=3和ko->b=ko->b&3等價(6和3使用二進位製作與(&)運算)

ko->c|=2;//同理5和2使用二進位製作或(|)運算,「、=」、「&=」是復合位運算

cout << ko->a << " " << ko->b << " " << ko->c << endl;

return 0;

位域的大小;

如果位域字段之間穿插著非位域字段,則不進行壓縮;

比如:struct k

;cout << sizeof(k) << endl;

結果為24

調換一下位置

struct k

;結果為16

一定要自己親自動手寫**才能正真理解哦。

記憶體對齊以及位域

首先我們大家先思考乙個問題,為什麼編譯器會有記憶體對齊這種東西呢?原因有二 一.平台原因 某些硬體平台只能在某些位址處取某些特定型別的資料,否則丟擲硬體異常。二.效能原因 如果訪問的是未對齊的記憶體,處理器需要做兩次記憶體訪問 如果記憶體對齊,則處理器只需要做一次記憶體訪問。許多計算機系統對基本型別...

位域位元組對齊

使用位域的主要目的是壓縮儲存,其大致規則為 1 如果相鄰位域字段的型別相同,且其位寬之和小於型別的sizeof大小,則後面的字段將緊鄰前乙個字段儲存,直到不能容納為止 2 如果相鄰位域字段的型別相同,但其位寬之和大於型別的sizeof大小,則後面的字段將從新的儲存單元開始,其偏移量為其型別大小的整數...

結構體位元組對齊和位域對齊 VC gcc

分類 c c 2012 10 13 15 34 474人閱讀收藏 舉報 1 什麼是位元組對齊 乙個變數占用 n 個位元組,則該變數的起始位址必須能夠被 n 整除,即 存放起始地 址 n 0,對於結構體而言,這個 n 取其成員中的資料型別佔空間的值最大的那個。2 為什麼要位元組對齊 記憶體空間是按照位...