首页 > 代码库 > C++面试题6:sizeof 使用规则及陷阱
C++面试题6:sizeof 使用规则及陷阱
C++面试题6:sizeof 使用规则及陷阱
cout << sizeof(int) << endl; //32位机上int长度是4cout << sizeof(1==2) << endl; //bool类型,相当于cout << sizeof(bool) << endl;1
陷阱:
int a=0;
cout << sizeof(a=3) << endl; //sizeof作用范围内,也就是括号里面的内容不能被编译,而是被替换成类型,=操作符返回左操作数的类型,所以a=3相当于int 4cout << a << endl; //输出0
结论:不要把sizeof当成函数,也不要看作一元操作符,把他当成一个特殊的编译预处理。
sizeof两种用法:
sizeof(object)
对对象使用sizeof(typename)
对类型使用,这里要注意一定要使用括号。
cout << sizeof int << endl; 错误,要加上()
cout << sizeof 2 << endl; 正确
结论:无论sizeof要对谁取值,最好加上()
数据类型的sizeof
32位C++中的基本数据类型,也就是char,short int(short), int, long int(long), float, double, long double
大小分别为1,2,4,4,8,10
cout<<sizeof(unsigned int) == sizeof(int)<<endl; // 相等,输出 1
结论:unsigned不影响sizeof的取值
int f1(){return 0;};
double f2(){return 0.0;}
void f3(){}
cout<<sizeof(f1())<<endl; // f1()返回值为int,因此被认为是intcout<<sizeof(f2())<<endl; // f2()返回值为double,因此被认为是doublecout<<sizeof(f3())<<endl; // 错误!无法对void类型使用sizeofcout<<sizeof(f1)<<endl; // 错误!无法对函数指针使用sizeof cout<<sizeof*f2<<endl; // *f2,和f2()等价,因为可以看作object,所以括号不是必要的。被认为是double
结论:对函数使用sizeof,在编译阶段会被函数返回值的类型取代
指针问题:
结论:主要是指针,大小就是4
数组问题:
char a[] = "abcdef";
int b[20] = {3, 4};
char c[2][3] = {"aa", "bb"};
cout<<sizeof(a)<<endl; // 7cout<<sizeof(b)<<endl; // 20*4cout<<sizeof(c)<<endl; // 6
结论:数组的大小是各维数的乘积*数组元素的大小。
陷阱:
int *d = new int[10];
cout<<sizeof(d)<<endl; // 4
这里一定要注意d是我们常说的动态数组,但是他实质上还是一个指针,所以sizeof(d)的值时4
指针数组问题:
double* (*a)[3][6]; //a是执行double*[3][6]类型数组的指针
cout<<sizeof(a)<<endl; // 4 a是执行double*[3][6]类型数组的指针
cout<<sizeof(*a)<<endl; // 72 *a是一个double*[3][6]多维数组类型3*6*sizeof(double*)=72cout<<sizeof(**a)<<endl; // 24 **a表示一个double*[6]类型数组 6*sizeof(double*)=24cout<<sizeof(***a)<<endl; // 4 ***a表示一个元素,也就是double*,4cout<<sizeof(****a)<<endl; // 8 ****ad表示一个double 所以大小为4
字符串的sizeof和strlen
char a[] = "abcdef";
char b[20] = "abcdef";
string s = "abcdef";
cout<<strlen(a)<<endl; // 6,字符串长度cout<<sizeof(a)<<endl; // 7,字符串容量cout<<strlen(b)<<endl; // 6,字符串长度cout<<sizeof(b)<<endl; // 20,字符串容量cout<<sizeof(s)<<endl; // 12, 这里不代表字符串的长度,而是string类的大小cout<<strlen(s)<<endl; // 错误!s不是一个字符指针。
a[1] = ‘\0‘;
cout<<strlen(a)<<endl; // 1cout<<sizeof(a)<<endl; // 7,sizeof是恒定的
总结:strlen是寻找从指定地址开始,到出现的第一个0之间的字符个数,在运行阶段执行的,而sizeof是得到数据的大小,在这里得到是字符串的容量。所以对于同一个对象而已,sizeof的值时恒定的,string是C++类型的字符串,它是一个类,strlen(s)是错误的,应该使用strlen(s.c_str())因为string的成员函数c_str()返回的是字符串的首地址;实际上string封装了常用的字符串操作,Capacity()和Length()。所以在开发过程中最好使用string代替C类型的字符串。
从union的sizeof问题看cpu的对界
union u
{
double a;
int b;
};
union u2
{
char a[13];
int b;
};
union u3
{
char a[13];
char b;
};
cout<<sizeof(u)<<endl; // 8cout<<sizeof(u2)<<endl; // 16cout<<sizeof(u3)<<endl; // 13
结论:复合数据类型,如union,struct,class的对齐方式为成员中对齐方式最大的成员的对齐方式。
struct的sizeof问题
struct s1
{
char a;
double b;
int c;
char d;
};
struct s2
{
char a;
char b;
int c;
double d;
};
cout<<sizeof(s1)<<endl; // 24cout<<sizeof(s2)<<endl; // 16
这里有一个陷阱:
对于结构体中的结构体成员,不要认为它的对齐方式就是他的大小,看下面的例子:
struct s1
{
char a[8];
};
struct s2
{
double d;
};
struct s3
{
s1 s;
char a;
};
struct s4
{
s2 s;
char a;
};
cout<<sizeof(s1)<<endl; // 8cout<<sizeof(s2)<<endl; // 8cout<<sizeof(s3)<<endl; // 9cout<<sizeof(s4)<<endl; // 16;
s1和s2大小虽然都是8,但是s1的对齐方式是1,s2是8(double),所以在s3和s4中才有这样的差异
结论:在自己定义结构体的时候,如果空间紧张的话,最好考虑对齐因素来排列结构体里的元素。
不要让double干扰你的位域
在结构体和类中,可以使用位域来规定某个成员所能占用的空间,所以使用位域能在一定程度上节省结构体占用的空间。不过考虑下面的代码:
struct s1
{
int i: 8;
int j: 4;
double b;
int a:3;
};
struct s2
{
int i;
int j;
double b;
int a;
};
struct s3
{
int i;
int j;
int a;
double b;
};
struct s4
{
int i: 8;
int j: 4;
int a:3;
double b;
};
cout<<sizeof(s1)<<endl; // 24cout<<sizeof(s2)<<endl; // 24cout<<sizeof(s3)<<endl; // 24cout<<sizeof(s4)<<endl; // 16
结论:有double存在会干涉到位域(sizeof的算法参考上一节),所以使用位域的的时候,最好把float类型和double类型放在程序的开始或者最后。
C++面试题6:sizeof 使用规则及陷阱