内存总结之返回对象占用字节数操作符sizeof

@著作权归作者所有:来自CSDN博客作者大胡子的艾娃的原创作品,如需转载,请注明出处https://blog.csdn.net/qq_43148810,否则将追究法律责任。
如有错误的地方欢迎指正,谢谢!

申明:sizeof() 是一个判断数据类型或者表达式长度的运算符。sizeof() 的处理都是在编译阶段进行。其作用就是返回一个对象或者类型所占的内存字节数。

一:sizeof求基本数据类型所占的内存字节数关系表。
大胡子的艾娃
但是sizeof(void)是非法的,没有人会定义一个void变量,void真正发挥的作用在于:对函数返回的限定;对函数参数的限定。
Visual Studio 2017上void a;//显示不允许使用不完整的类型,并且会报错C2182,非法使用"void"类型。

二、sizeof求指针所占的内存字节数
1、32位系统为4,64位系统则为8。
2、所有的指针变量所占内存大小相等,因为指针变量的sizeof值与指针所指的对象没有任何关系。

三、sizeof求enum枚举类型所占的内存字节数
1、枚举类型,本质上是一组常数的集合体,只是这些常数有各自的命名。枚举类型,是一种用户自定义数据类型。
2、枚举变量,由枚举类型定义的变量。枚举变量的大小,即枚举类型所占内存的大小。由于枚举变量的赋值,一次只能存放枚举结构中的某个常数。所以枚举变量的大小,实质是常数所占内存空间的大小,枚举类型所占内存大小也是这样。

四、sizeof求array数组所占的内存字节数
1、数组的sizeof值等于数组所占用的内存字节数==元素类型大小*元素个数。
2、当字符数组表示字符串时,其sizeof值将’/0’计算进去。
3、数组名作为实参传入函数时,会自动转化为指针类型,所以其sizeof值相当于指针的sizeof值。

五、sizeof求union联合体所占的内存字节数
1、联合体union性质
a、联合体所有成员变量共享内存,相对于联合体首地址偏移量都为0。
b、同一时间只能存储1个被选择的变量,对其他成员变量赋值会覆盖原变量。

2.联合体大小计算准则
a、联合体大小要至少能容纳最大的成员变量。
b、复合数据类型,如union、struct、class的对齐方式为成员中最大的成员对齐方式。(数组可以理解为多个相同成员的集合)。

3、对齐是可以更改的,使用#pragma pack(x)可以改变编译器的对其方式。

六、sizeof求struct结构体所占的内存字节数
1、结构体的sizeof涉及到字节对齐问题。
为什么需要字节对齐?计算机组成原理教导我们这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,依次类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。

2、字节对齐的细节和编译器的实现相关,但一般而言,满足三个准则:
a、结构体变量的首地址能够被其最宽基本类型成员的大小所整除。
b结构体的每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要,编译器会在成员之间加上填充字节(internal adding)。
c、结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要,编译器会在最末一个成员后加上填充字节(trailing padding)。

注意:空结构体(不含数据成员)的sizeof值为1。试想一个“不占空间“的变量如何被取地址、两个不同的“空结构体”变量又如何得以区分呢,于是,“空结构体”变量也得被存储,这样编译器也就只能为其分配一个字节的空间用于占位了。

d、C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型类型的存在。使用位域的主要目的是压缩存储,其大致规则为:
(1)如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止
(2)如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍。
(3)如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式。
(4)如果位域字段之间穿插着非位域字段,则不进行压缩。
(5)整个结构体的总大小为最宽基本类型成员大小的整数倍。
还是让我们来看看例子。
示例1:
struct BF1{char f1:3;char f2:4;char f3:5;};
其内存布局为:
大胡子的艾娃
位域类型为char,第1个字节仅能容纳下f1和f2,所以f2被压缩到第1个字节中,而f3只能从下一个字节开始。因此sizeof(BF1)的结果为2。
示例2:
struct BF2{char f1:3;short f2:4;char f3:5;};
由于相邻位域类型不同,在VC6中其sizeof为3,在Dev-C++中为2。
示例3:
struct BF3{char f1:3;char f2;char f3:5;};
非位域字段穿插在其中,不会产生压缩,在VC6和Dev-C++中得到的大小均为3。

七、sizeof求class类的对象所占的内存字节数
1、c++中类所占的大小计算涉及到虚函数成员,静态成员,虚继承,多继承以及空类等。

2、声明的类只是一种类型定义,它本身是没有大小可言的。这里指的类的大小,其实指的是类的对象所占的大小。

3、关于类/对象大小的计算
a、首先,类大小的计算遵循结构体的对齐原则
b、类的大小与普通数据成员有关,与成员函数和静态成员无关。
d、即普通成员函数,静态成员函数,静态数据成员,静态常量数据成员均对类的大小无影响。
e、虚函数对类的大小有影响,是因为虚函数表指针带来的影响。
f、虚继承对类的大小有影响,是因为虚基表指针带来的影响
g、空类的大小是一个特殊情况,空类的大小为1

4、sizeof求STL中的string类的对象所占的内存字节数
Visual Studio中普遍是28字节,VC 6.0算出来的是16字节,有些书上是4字节。

提示:capacity()容量默认容量大小(Visual Studio2015),少于15个,申请15个容量(至少申请15个),以后容量不足就增加当前的1/3大小,直到容量足够。VC++6.0 是至少申请31个空间,以后每次增加32个。
容量是指string对象不改变存储地址所能容纳最大字符串数量,>=string.size()求得数。
STL中的vector,list,deque,map,set等自己总结。

八、sizeof与strlen的区别
1、strlen(char*)函数求的是字符串的实际长度,直到遇到第一个’\0’,然后就返回计数值,且不包括’\0’。而sizeof()函数返回的是变量声明后所占的内存数,不是实际长度。
2、sizeof是算符,strlen是函数。
3、sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以’’\0’'结尾的;sizeof还可以用函数做参数。
4、数组做sizeof的参数不退化,传递给strlen就退化为指针了。
5、大部分编译程序在编译的时候就把sizeof计算过了是类型或是变量的长度,结果可以sizeof(x)结果可以用来定义数组维数,strlen的结果要在运行的时候才能计算出来,是用来计算字符串的长度,不是类型占内存的大小。

九、其他提示拓展
1、sizeof 无法获取动态分配的内存大小,即使用malloc/new动态的分配内存,无法使用sizeof获取其大小。
2、vs2017中“ char* str = “1234asd56”; ” 会报错:"const char*"类型的值不能用于初始化"char*"类型的实体,但是VS2015及其以前的版本都不会报错警告之类的。

本文只是用sizeof带出C++内存部分的知识,作为一名优秀的C++程序员,应该要非常清楚内存相关的知识,本文就算是抛砖引玉,希望大家在这方面深入研究。

更多内容请关注个人博客:https://blog.csdn.net/qq_43148810

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章