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
using namespace std;
float FuncP(int a, float b)
{
return a + b;
}
int FuncNP()
{
return 3;
}
void Func()
{
}
int main()
{
cout<