C語言中內存對齊方式

內存對齊,因爲它是對C/C++程序員透明的,在很多C,C++課本中也沒有講清楚,所以今天寫了這篇博客,講述爲什麼需要內存對齊,內存對齊怎麼計算?奮鬥

爲什麼需要內存對齊?

1、平臺原因(移植原因):不是所有的硬件平臺都能訪問任意地址上的任意數據的。某些硬件平臺只能在某些地址處取某些特定類型的數據,否則拋出硬件異常。
2、性能原因:數據結構(尤其是棧)應該儘可能地在自然邊界上對齊。原因在於,爲了訪問未對齊的內存,處理器需要作兩次內存訪問;而對齊的內存訪問僅需要一次訪問。

內存對齊怎麼計算?

首先,需要知道內存對齊的四個準則:

1.第一個成員與結構體變量的偏移量爲0

2.其他變量要對齊到對齊數(對齊數取編譯器預設的一個對齊整數與該成員大小的較小值)的整數倍地址

3.結構體總大小爲最大對齊數的整數倍

接下來通過幾個例子來說明問題:(在4字節的32位機上)

#include <iostream>
#include<stdio.h>
using namespace std;

struct Test
{
	int a;
	char b;
	short c;
};

int main(void)
{
	Test test;
	printf("a=%p\n", &test.a);
	printf("b=%p\n", &test.b);
	printf("c=%p\n", &test.c);
	cout << sizeof(Test) << endl;
	return 0;
}

輸出結果:


分析過程:

1、首先確定每個成員的有效對齊值,由於這裏沒有指定對齊值 所以 每個成員的有效對齊值就是其自身數據類型的對齊值
a 的對齊值是 4字節(32位機上) b 的對齊值是 1字節 c 的對齊值是2字節
2、起始地址必須滿足“起始地址%N = 0”
令起始地址位0x0000  按照變量的順序存儲 則 0x0000%4 = 0;滿足條件 佔用4個字節 0x0000-0x0003 折四個字節
變量b 的起始地址 是 0x0004%1 = 0滿足條件 佔用一個字節 就是0x0004
變量c 的起始地址 是 0x0005%2 !=0 所以起始地址要向後移位 知道滿足條件位置 0x0006%2 = 0 滿足條件 佔用2字節 0x0006- 0x0007
總共佔用了8字節

如果變換爲這樣:

#include <iostream>
#include<stdio.h>
using namespace std;

struct Test
{
	
	char b;
	int a;
	short c;
};

int main(void)
{
	Test test;
	printf("a=%p\n", &test.a);
	printf("b=%p\n", &test.b);
	printf("c=%p\n", &test.c);
	cout << sizeof(Test) << endl;
	return 0;
}
輸出:


分析過程:

1、找變量的有效對齊位
 還是沒有指定對齊值 所以就是變量自身的對齊值 b 1字節, a 4字節,c 2字節
2、起始地址滿足 對有效對齊值取餘=0的條件
 令其實地址爲0x0000 % 1 = 0滿足 
變量a 的起始地址爲0x0001 %4 !=0
 則其實地址要向後移位 知道滿足條件爲止 0x0004%4 = 0 佔用4個字節 0x0004-0x0007
變量c 的起始地址爲 0x0008 %2
 = 0 滿足條件 佔用兩個字節 0x0008-0x0009
總共佔用了10個字節的內存空間
3、圓整 結構體的有效對齊值是4 所以 總共佔用的硬爲(10+2)%4
 = 0個字節 12個字節 

再來看以下幾個例子練習下:(以下例子是在VS2013上寫的,默認成員內存對齊爲8)

例子1:


輸出:16

例子2:


輸出:24

例子3:


輸出:16


輸出:12

附錄:微軟經典面試題:

#include <iostream.h>

#pragma pack(8)

struct example1

{

short a;

long b;

};

struct example2

{

char c;

example1 struct1;

short e;

};

#pragma pack()

int main(int argc, char* argv[])

{

example2 struct2;

cout << sizeof(example1) << endl;

cout << sizeof(example2) << endl;

cout << (unsigned int)(&struct2.struct1) - (unsigned int)(&struct2) << endl;

return 0;

}
輸出:

8

16

4

在網絡程序中,掌握這個概念可是很重要的喔,在不同平臺之間(比如在Windows 和Linux之間)傳遞2進制流(比如結構體),那麼在這兩個平臺間必須要定義相同的對齊方式,不然莫名其妙的出了一些錯的······

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章