內存對齊規則
- 變量(結構體變量)的起始地址能夠被其對齊值整除,結構體變量的對齊值為最寬的成員大小
- 結構體每個成員相對於起始地址的偏移能夠被其自身對齊值整除,如果不能則在前一個成員后面補充字節
- 結構體總體大小能夠被最寬的成員的大小整除,如不能則在后面補充字節
此外還有編譯器的默認對齊值,一般默認對齊值為4(結構體的實際對齊值會取結構體對齊值和編譯器默認對齊值中較小的那一個)。
內存對齊好的處
- 為了減少使用的內存
- 為了提升數據讀取的效率
#include <iostream> using namespace std; struct A { char c; short a; int i; }; int main() { A c; cout<<alignof(c.a)<<endl;//獲取字節對齊方式 cout<<sizeof(A)<<endl; return 0; } //8
#include <iostream> using namespace std; struct A { char c; int i; short a; }; int main() { A c; cout<<alignof(c.a)<<endl;//獲取字節對齊方式 cout<<sizeof(A)<<endl; return 0; } //12
double類型的數組(double類型為8字節對齊), 其在內存中所處的位置如下
數組的首地址為2,根據原則1數組未對齊。若CPU每次從內存中為8字節整數倍的地址開始讀入8字節的數據,則每次從未對齊的數組中讀取一個成員都要進行兩次讀取操作,而從對齊的數組中讀取則只需要一次讀取操作,數組對齊時讀取效率有較大提升
使用位域的主要目的是壓縮存儲,其大致規則為:
- 如果相鄰位域字段的類型相同,且其位寬之和小於類型的sizeof大小,則后面的字段將緊鄰前一個字段存儲,直到不能容納為止;
- 如果相鄰位域字段的類型相同,但其位寬之和大於類型的sizeof大小,則后面的字段將從新的存儲單元開始,其偏移量為其類型大小的整數倍;
- 如果相鄰的位域字段的類型不同,則各編譯器的具體實現有差異,VC6采取不壓縮方式,Dev-C++采取壓縮方式;
- 如果位域字段之間穿插着非位域字段,則不進行壓縮;
- 整個結構體的總大小為最寬基本類型成員大小的整數倍。
typedef struct AA{ unsigned char b1:5; unsigned char b2:5; unsigned char b3:5; unsigned char b4:5; unsigned char b5:5; }AA;/*sizeof(AA) = 5*/ typedef struct BB { unsigned int b1:5; unsigned int b2:5; unsigned int b3:5; unsigned int b4:5; unsigned int b5:5; }BB;/*sizeof(BB) = 4*/ typedef struct CC { int b1:1; int :2;//無影響 int b3:3; int b4:2; int b5:3; short b6:4; int b7:1; }CC; /*sizeof(CC) = 12*/
大端:高字節在起始地址(也就是低地址)
小端:低字節在起始地址(也就是低地址)
#include <stdio.h> #include <stdlib.h> using namespace std; int main() { union Test { int num; char str[4]; }T; T.num = 0x12345678; printf("%0x %0x %0x %0x\n", T.str[0], T.str[1], T.str[2], T.str[3]); printf("%p\n",&T.num); printf("%p\n",&T.str[0]); printf("%p\n",&T.str[1]); printf("%p\n",&T.str[2]); printf("%p\n",&T.str[3]); return 0; }