C++关键字sizeof
序言:这个系列的博客将记录C++中比较难懂的、不易理解的、尤其出错的一些知识点。上一个博客我们介绍了const关键字,这个关键字在C++的海洋里非常重要。但是它牵扯到的知识点很多,尤其指针、内存这些较难的知识点。因此在后面我也会树形结合的总结一下C/C++中内存存储的重要性。当然这次博客总要讲解sizeof运算符。
sizeof并非函数!而是一个运算符。它的作用是返回一条表达式或者一个类型名字所占的字节数。sizeof运算符满足右结合律,其所得的值是一个size_t类型的常量表达式。表现形式如下:
sizeof(type)
sizeof expr
sizeof返回的是是表达式结果类型的大小,最重要的是,sizeof并不会去计算运算对象的值。
int a,*p;
sizeof a;
sizeof p;
sizeof *p; //sizeof满足右结合律并且与*的运算符的优先级一样。等价于sizeof (*p);
了解了最基本的知识点之后,我们再来总结一下sizeof一些非常隐蔽的11个易错点。
易错点一:
char类型或者类型为char的表达式(包括unsigned char)执行sizeof运算。结果为1,其他的类型由编译器决定。
易错点二:
sizeof是运算符,并不是一个函数。不要与strlen()混淆。
易错点三:
sizeof能对void 类型求值?不确定。
如果回答最好的答案只能回答这样回答。因为标准是说:好吧,这规定的太多可不能让编译器闲着”避暑“。然后,标准就把能不能对void类型求值的这个问题丢给了编译器。编译器太多啦,我只能说gcc中是可以求值,这个值是1。其他的编译器可以试试。
事实上这个问题取决void类型。C语言中没有面向对象的思维,没有类、没有重载。那如何来实现在C语言中通用化的设计呢?答案是void类型。
void a ; //error!因为是不知道什么类型,所以无法存储!
易错点四:
sizeof能够求的void 类型的指针的长度,对指针进行sizeof执行sizeof运算将得到指针本身所占用的存储大小。
易错点五:
对解引用指针进行sizeof运算,将会得到指针所指向对象的所占用的空间的大小,指针不需要有效。
易错点六:
sizeof能够求的静态分配的数组的长度的长度。
这里我们使用的最多的就是求取数组的个数,通常用来在for循环中遍历数组非常的有效。
char array[5]={a,b,c,d,};
int n = sizeof(array)/sizeof(array[0]);
非常注意的一点是,数组可以隐式的转换为指针。例如:
int fun(char array[5])
{
int n = sizeof(array); //传进来的时候,array转变一个地址。
}
易错点七:
sizeof不能动态分配的数组的长度。
sizeof刚刚出现的时候,是在编译的时候求值,但是在C99的标准中,又可以规定sizeof可以在运行时求值。
易错点八:
当对表达式作为sizeof()的操作数的时候,它返回的是表达式的计算结果的类型。但是并不会对表达式求值。
易错点九:
对函数求sizeof的时候,不回调用函数体。这又是与编译器相关的,在gcc中,对函数进行sizeof运算的时候,得出的结果为1。
易错点十:
sizeof求的结构体的大小并不会等于结构体中的各个成员的数据成员的对象的大小之和。
原因是因为结构体中存在对齐。后面我将继续讲解结构体中内存的存储方式,再次提及。
易错点十一:
sizeof不能求解结构体中位域成员的大小,但是可以求解的它包含位域成员的结构体的大小。
对于结构体中的知识点,我后面会采取树形结合的记录,会更好,原来打算是最开始记录这方面的知识,可是画图的功夫还有点差,画出来就见不得人。
小结:
本次记录了sizeof如何去理解,我们发现sizeof是与编译器高度的相关。这才是这次博客的重点,当我们去深入的学习C++的时候,需要的关注的是语言的标准和编译器的标准,同时能从内存的观点上看待事物就能够取得进步。