1. 定義
sizeof 是一個操作符 operator,不是一個函數,
其作用是返回一個對象或類型所占的內存字節數
---------------------------------------------------------------------------------------------------------
2. 語法
sizeof object; //sizeof 對象
sizeof(object);
sizeof(type_name); // 例如 sizeof(int)
對象 object 可以是各種類型的變量,以及表達式(一般sizeof
不會對表達式進行計算);sizeof
對對象求內存大小,最終都是轉化為對對象的數據類型進行求值;sizeof(表達式) 值為表達式的最終結果的數據類型的大小
int i;
sizeof(int); //值為4
sizeof(i); //值為4,等價於sizeof(int)
sizeof i; //值為4
sizeof(2); //值為4,等價於sizeof(int),因為2的類型為int
sizeof(2 + 3.14); //值為8,等價於sizeof(double),因為此表達式的結果的類型為double
char ary[sizeof(int) * 10]; //OK,編譯無誤
---------------------------------------------------------------------------------------------------------
3. 基本數據類型的 sizeof
基本數據類型如int
short
long
char
double
等,其內存大小與系統有關。32位系統的int(4 Bytes), short(2 Bytes), long(4 Bytes), char(1 Bytes), double(8 Bytes), float(4 Bytes)
4. 結構體的 sizeof
結構體的 sizeof
涉及到字節對齊問題,字節對齊有助於加快計算機的存取速度,減小指令周期。為此,編譯器會默認對結構體進行處理(實際上上其他地方的數據量也是如此),讓寬度為 2 的基本數據類型(如short
等)都位於能被 2 整除的地址上,讓寬度為 4 的基本數據類型(如int
等)都位於能被 4 整除的地址上,以此類推,這樣,兩個數中間就要加入填充字節,所以整個結構的sizeof
值就比實際數據類型的內存值要大
字節對齊的細節和編譯器的實現有關,但一般而言,滿足3個准則:
- 結構體變量的首地址能夠被最寬基本類型成員的大小所整除
- 結構體的每個成員相對於結構體首地址的偏移量都是成員大小的整數倍,如有需要,編譯器會在成員之間填充字節(internal adding)
- 結構體的總大小為結構體最寬基本類型成員大小的整數倍,如有需要,編譯器會在最末一個成員上加上填充字節(trailing padding)
注意:空結構體(不含數據成員)的 sizeof
值為 1 ,試想一個“不占空間“的變量如何被取地址、兩個不同的“空結構體”變量又如何得以區分呢,於是,“空結構體”變量也得被存儲,這樣編譯器也就只能為其分配一個字節的空間用於占位了。
struct S1
{
char a;
int b;
};
sizeof(S1); //值為 8,字節對齊,在char之后會填充 3 個字節。
//-----------------------------------------------------------------------------------------
struct S2
{
int b;
char a;
};
sizeof(S2); //值為 8,字節對齊,在char之后會填充 3 個字節。
//-----------------------------------------------------------------------------------------
struct S3
{
};
sizeof(S3); // 值為 1,空結構體也占內存
//-----------------------------------------------------------------------------------------
struct S4
{
char a;
int b;
float c;
double d;
};
sizeof(S4); //值為 24,在 a 后面補 3 個字節,在 c 和 d 之間補 4 個字節
struct S4_1
{
double a;
char b;
int c;
float d;
};
sizeof(S4_1);// 值為24, 在 b 后面補3個字節,為了使整體大小能夠被最寬的double 8整除,需要在最后面加4個字節。
struct S4_2
{
int a;
double b;
float c;
};
sizeof(S4_2);// 值為 24, 為了使double 的相對於首地址的偏移能夠整除 8,在 a 后面補 4 個字節,為了使整體大小能夠被最寬的double 8整除,需要在最后面加 4 個字節。
struct S4_3
{
double d;
int b;
float c;
};
sizeof(S4_3); //值為 16,滿足條件,不需要填補。
//-----------------------------------------------------------------------------------------
struct S5
{
char a;
S4_3 b;
int c;
};
sizeof(S5); // 值為 32, 要滿足結構體 S4_3的首地址可以被其最寬成員 double 8整除,在 a 后應該填充 7 個字節
//然后為了滿足總的成員大小能夠被最寬成員 double 8 整除,在 int 后需要填充 4 個字節
---------------------------------------------------------------------------------------------------------
5. 聯合體的sizeof
結構體在內存組織上是順序式的,聯合體是重疊式的,各成員共享一段內存,所以整個聯合體的sizeof
就是每個成員sizeof
的最大值
union u
{
int a;
float b;
double c;
char d;
};
sizeof(u); // 值為 8
---------------------------------------------------------------------------------------------------------
6. 指針的sizeof
指針是用來記錄另外一個對象的地址,所以指針的內存大小就是計算機內部地址總線的寬度
在32位計算機中,一個指針的sizeof
返回值必定是4
指針變量的sizeof
值與指針所指的對象沒有任何關系
注意,數組名不等同於指針,其在sizeof
下不一致
char *b = "helloworld";
sizeof(b); // 指針指向字符串, 值為 4
sizeof(*b); // 指針指向字符`h`,值為 1
//--------------------------------------------------------------------------------------
char a[10] = "hello";
sizeof(a); // 值為 10,數組名表示指向大小為10個字符的數組
sizeof(*a); // 值為 1,*a 指向數組的第一個字符
//---------------------------------------------------------------------------------------
char *c[10];
sizeof(c); // 值為 40,c表示指向具有10個指針的指針數組,每個指針的大小為4,因此為40
sizeof(*c); // 值為 4,*c 指向指針數組的第一個元素
//-----------------------------------------------------------------------------------------
double *d;
sizeof(d); // 值為 4, 指向 double 的指針
sizeof(*d); // 值為 8,*d 表示一個 double 的浮點數
//-----------------------------------------------------------------------------------------
char **e;
sizeof(e); // 值為 4,e 指向指針的指針
sizeof(*e); // 值為 4,*e 指向char字符的指針
sizeof(**e); // 值為 1,**e 表示 char 字符
//-----------------------------------------------------------------------------------------
char a1[] = "abc";
int a2[3];
sizeof( a1 ); // 結果為4,字符 末尾還存在一個NULL終止符
sizeof( a2 ); // 結果為3*4=12(依賴於int)
void foo(char a[])
{
int b= sizeof( a ); // b == 4
}
void (*pf)();
sizeof(pf); // 值為 4,指向函數的指針
---------------------------------------------------------------------------------------------------------
7. 數組的sizeof
數組名與指針不等同,數組名指向具有一定大小的數組,比指針多了數組長度
//--------------------------------------------------------------------------------------
char a[10] = "hello";
sizeof(a); // 值為 10,數組名表示指向大小為10個字符的數組
sizeof(*a); // 值為 1,*a 指向數組的第一個字符
//---------------------------------------------------------------------------------------
char *c[10];
sizeof(c); // 值為 40,c表示指向具有10個指針的指針數組,每個指針的大小為4,因此為40
sizeof(*c); // 值為 4,*c 指向指針數組的第一個元素
//---------------------------------------------------------------------------------------
char a1[] = "abc";
int a2[3];
sizeof( a1 ); // 結果為4,字符 末尾還存在一個NULL終止符
sizeof( a2 ); // 結果為3*4=12(依賴於int)
void foo(char a[])
{
int b= sizeof( a ); // b == 4,數組作為形參時,只傳遞地址指針,因此為 4,一般我們會再添加數組長度作為形參
}
---------------------------------------------------------------------------------------------------------
8. 函數的 sizeof
sizeof
對函數函數求值,其結果是函數返回值類型的大小,函數並不會被調用- 注意:
- 不能對函數返回值為空的函數求值
- 不能對函數名求值
- 對有參數的函數,在用
sizeof
時,必須寫上實參表
#include <iostream>
using namespace std;
float FuncP(int a, float b)
{
return a + b;
}
int FuncNP()
{
return 3;
}
void Func()
{
}
int main()
{
cout<<sizeof(FuncP(3, 0.4))<<endl; //OK,值為4,sizeof(FuncP(3,0.4))相當於sizeof(float)
cout<<sizeof(FuncNP())<<endl; //OK,值為4,sizeof(FuncNP())相當於sizeof(int)
/*cout<<sizeof(Func())<<endl; //error,sizeof不能對返回值為空類型的函數求值*/
/*cout<<sizeof(FuncNP)<<endl; //error,sizeof不能對函數名求值*/
return 0;
}
void (*pf)();
sizeof(pf); // 值為 4,指向函數的指針