1.基本類型
sizeof運算符返回類型或者數據對象的長度(字節),
int a=1;
float b=1.0;
double c=1.0;
long d=1;
char e = '1';
cout<<sizeof(a)<<" "<<sizeof(b)<<" "<<sizeof(c)<<" "<<sizeof(d)<<" "<<sizeof(e)<<endl;
cout<<sizeof(int)<<" "<<sizeof(float)<<" "<<sizeof(double)<<" "<<sizeof(long)<<" "<<sizeof(char)<<endl;
輸出:
4 4 8 8 1
4 4 8 8 1
2.靜態數組
將sizeof運算符用於靜態數組名,得到的是整個數組的字節數,用於數組元素,則得到的是元素長度。
int arr[3]={1,1,1};
float arr1[3]={1.0,1.0,1.0};
double arr2[3]={1.0,1.0,1.0};
cout<<sizeof(arr)<<" "<<sizeof(arr1)<<" "<<sizeof(arr2)<<endl;
cout<<sizeof(arr[0])<<" "<<sizeof(arr1[1])<<" "<<sizeof(arr2[2])<<endl;
輸出:
12 12 24
4 4 8
3.動態數組
但是當sizeof運算符用於動態數組,就很神奇。
vector<int>arr1(1,0);
vector<int>arr2(2,0);
vector<int>arr3(3,0);
cout<<sizeof(arr1)<<" "<<sizeof(arr2)<<" "<<sizeof(arr3)<<endl;
輸出:
24 24 24
可以看到不管vector有多少元素,輸入都是24,爲啥?
這是因爲 vector 是C++標準庫中的容器類,其內部實現了三個指針,
- start;
- finish;
- end_of_storage;
分別代表頭, 尾(實際使用), vector 存儲尾部(佔用的,通常大於實際使用),finish-start對應於size(),end_of_storage-start對應於capacity(),如下圖所示:
vector 通過配置比其所容納的元素所需更多的內存,即先預留足夠空間,避免二次分配,從而提高 vector 的性能。
so,sizeof(vec)其實得到的是三個指針佔用內存。在64bit系統中,一個指針佔用8個字節。
4.結構體
結構體成員是按照定義時的順序依次存儲在連續的內存空間,但是結構體大小並不是所有成員大小之和。這涉及字節對齊的問題。
4.1 偏移量
偏移量指的是結構體成員地址與結構體地址的差值。結構體大小等於最後一個成員的偏移量加上最後一個成員的大小。顯然,結構體變量中第一個成員的地址就是結構體變量的首地址。
4.2 字節對齊
字節是計算機內存的基本單位,但是並不是逐個字節存取,而是一次性存取4字節(32位系統),8個字節(64位系統),這樣子也對訪問地址做了限制,它必須是4,8的倍數。
如果數據地址不是4,8倍數會怎麼樣?
考慮64位系統,若沒內存對齊規則,如果你的數據地址在0x0001-0x0008,因爲地址不是0x0000開頭,所以只能分別在0x0000-0x0007和0x0008-0x0015去兩次數據,然後剔除多餘數據,再把結果返回給你,這樣子使得IO變慢。因爲計算機CPU速度遠遠快於內存讀寫速度,所以減少內存訪問次數是提升執行速度的關鍵。
按照對齊規則存取數據,將數據放在0x0000-0x0008,則可一次性取出,減少訪問次數,提升性能。
以下引用於C/C++內存對齊詳解
每個特定平臺上的編譯器都有自己的默認“對齊係數”(也叫對齊模數)。gcc中默認#pragma pack(4),可以通過預編譯命令#pragma pack(n),n = 1,2,4,8,16來改變這一系數。
有效對其值:是給定值#pragma pack(n)和結構體中最長數據類型長度中較小的那個。有效對齊值也叫對齊單位。
字節對齊規則如下
1.第一個結構體成員的地址偏移量爲0,以後每個成員偏移量都是成員大小或者有效對齊字節數的最小值的整數倍。如有需要編譯器會在成員之間加上填充字節。
2.結構體總大小是有效對齊值的整數倍。如有需要編譯器會在最末一個成員之後加上填充字節。
舉幾個例子
#例1
struct stru
{
int a;
char b;
int c;
}
例1,a偏移量爲0,佔用地址空間爲0-3,然後b偏移量爲4(成員的大小<有效對齊字節),佔用地址空間爲4,c偏移量不爲5,而是8,佔用地址空間爲8-11,佔用了12個字節,又是有效對齊值的整數倍。
#例2
struct stru
{
char a;
int b;
int c;
}
例2,a偏移量爲0,佔用地址空間爲0,然後b的偏移量也不能是1,而是4,b佔用的地址空間爲4-7,c偏移量爲8,佔用地址空間爲8-11,佔用了12個字節。
#例3
struct stru
{
int a;
char b;
char c;
}
例3,a佔用4個字節,地址爲0,b偏移量爲4(成員大小<有效對齊字節),佔用地址空間爲4,c偏移量爲5(成員大小<有效對齊字節),所以共5個字節,但是需要填充3個字節,所以例3結構大小爲8。
#例4
struct stru
{
char a;
int b;
char c;
}
例4,a的偏移量爲0,佔用地址空間爲0,但是b的偏移量不能是2了,應該是4,佔用地址空間爲4-7,然後c偏移爲8,共佔用了9個字節,但是整個結構體成員大小爲12。