概述
在学习C语言时,老师讲解sizeof时还以为就是一个普通的运算符,只是用来计算所占字节的,现在看来要么我当时在睡觉,要么我灵魂在出窍。在找工作笔试的过程中,总是会碰到关于sizeof用法的各种题目,碰到比较难度比较大的题目时,曾经一度的怀疑人生。现在就把这个运算符的使用归纳一下,以免以后还怀疑人生。
概念及语法
定义:sizeof运算符返回一条表达式或一个类型名字所占的字节数。返回值是一个size_t类型的常量表达式。
根据其定义就能看出来,语法分为两种形式:
sizeof (type) 返回类型的大小
sizeof expr 返回表达式结果类型的大小
例如:
Sales_data data, *p;
sizeof(Sales_data); //存储Sales_data类型的对象所占的空间大小
sizeof data; //data的类型的大小,即sizeof(Sales_data)
sizeof p; //指针所占空间的大小
sizeof *p; //p所指类型的空间大小,即sizeof(Sales_data)
sizeof data.revenue; //Sales_data的revenue成员对应的类型大小
sizeof Sales_data::revenue; //另一种获取revenue大小的方式
通过最后一个例子可以看出,sizeof允许我们使用作用域运算符来获取类成员的大小。通常情况下只有通过类的对象才能访问到类的成员但是sizeof运算符无须我们提供一个具体的对象。
注意:sizeof 并不实际计算其运算对象的值,例如:
int a = 0;
cout << sizeof(a = 3) << endl; //4
cout << a << endl; //0 sizeof并不实际计算
输出的结果为4 和 0。原因是C/C++是静态强类型语言,所有数据类型的占用空间大小都是确定的。同时sizeof的计算发生在编译器时刻,编译器知道类型的大小,所以sizeof计算的类型大小在编译器的时刻就知道了。回应了前面sizeof的定义,返回值是一个常量表达式。
C99标准规定,函数类型、不能确定类型的表达式以及位域成员不能被计算sizeof值。估计都看晕了,举例说明吧:
int foo()
{
retrun 1;
}
sizeof(foo); //错误,编译通不过
void foo2(){}
sizeof(foo2() ); //错误
struct S
{
unsigned int f1 : 1;
unsigned int f2 : 5;
unsigned int f3 : 12;
}
sizeof(S.f1); //错误
下面让我们从各个角度对sizeof进行解析,说明一下有时在不同位数的系统下,sizeof的计算会有差别,如果没有特别声明的话默认为32位系统。
1、基本数据类型的sizeof
基本数据类型是指char、short、int、float、double、long double这样的内置数据类型。
由于他们有的内存大小和系统有关,所以在不同的系统下取值可能不一样。
在32位和64位机器上对应的大小都是:1、2、4、4、8、8
但在16位机器上就有差别了。
bool值,在C++中属于内置类型,数值为true和false,sizeof大小为1。在C中不属于内置类型,数值为1和0,sizeof应该为4(我没有验证这个)。
至于整形的可用修饰词unsigned,它只影响最高位bit的意义,所占长度不会改变。
2、自定义数据类型
用typedef或using定义的自定义类型,例如
typedef short WORD;
using DWORD = long;
cout<<(sizeof(short) == sizeof(WORD))<<endl; // 相等,输出 1
cout<<(sizeof(long) == sizeof(DWORD))<<endl; // 相等,输出 1
所以自定义类型的sizeof取值等同于它的类型原形。
3、指针变量的sizeof
指针是存储单元的地址,sizeof指针变量就等于计算机内部地址总线的宽度。所以在32位计算机中,一个指针变量的返回值固定是4。同理在64位系统中,返回值必定为8。
例如,在32位系统下: