首页 > 代码库 > 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是8double),所以在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 使用规则及陷阱