C++:关于sizeof

来源:互联网 发布:ubuntu 播放器推荐 编辑:程序博客网 时间:2024/06/01 15:53

关于sizeof


sizeof运算符返回一条表达式或者一个类型名字所占的字节数,满足右结合律,返回值是一个size_t类型的常量表达式。sizeof 并不会对运算对象进行实际的求值运算。sizeof的计算通常发生在编译时刻,可以被当作常量表达式来使用,存在两种表达方式:
sizeof (type);
sizeof expr; 


1)对char或者类型为char的表达式执行sizeof运算,其结果为1;
2)对引用类型进行sizeof操作得到的是被引用对象所占空间的大小;
3)对指针执行sizeof运算得到的是指针本身所占空间的大小;
4)对解引用指针执行sizeof运算得到的是指针所指对象所占空间的大小,其中指针并不一定需要有效;
5)对数组(数组名)执行sizeof操作得到整个数组所占空间的大小;
6)对string或者vector对象执行sizeof操作只返回该类型固定部分的大小,不会计算其中元素占用的空间。

一、32/64位系统

32、64位操作系统,不同类型变量对应的字节数为:(红色的表示与32位系统不同之处)

char :1个字节 (32、64位)
指针变量: 、4字节(32位)、8个字节 (64位)
short int : 2个字节 (32、64位)
int: 4个字节 (32、64位)
unsigned int : 4个字节 (32、64位)
unsigned long: 8个字节(32、64位)
long: 4字节(32位)、8个字节(32、64位)
long long: 8个字节(32、64位)
float: 4个字节 (32、64位)
double: 8个字节(32、64位)
long double: 8字节(32位)、16个字节(位)

二、字节对齐

计算机存储系统中以Byte为单位存储数据,不同数据类型所占的空间不同。计算机为了快速的读写数据,默认情况下将数据存放在某个地址的起始位置,如整型数据(int)默认存储在地址能被4整除的起始位置,字符型数据(char)可以存放在任何地址位置(被1整除),短整型(short)数据存放在地址能被2整除的起始位置。这就是默认字节对齐的方式。

1、数据类型自身的对齐值

不同系统的对齐值不同。在32位系统中,对于char类型,自身对齐值为字节;对于short类型,自身对齐值为2字节;对于int、float类型,自身对齐值为4字节。

2、结构体或者类的自身对齐值

其成员中自身对齐值最大的那个值,包括是复合类型的成员(如其他结构体)。

3、指定对齐值

#pragma pack(n)


三、常见类型的sizeof

1、基本内置数据类型

基本的数据类型如short 、int、long、float、double等简单的内置数据类型,由于其所占的内存大小和使用的系统有关,因此在不同的系统中取值可能不同,在使用的时候尽量考虑代码的遗植问题。


2、指针类型的sizeof

指针类型存放的指向一个对象的地址,在32位系统中,地址为4字节;在64位系统中,地址为8字节。使用sizeof时不用考虑指针指向的是什么类型的数据。


3、数组的sizeof

数组的sizeof值就是数组本身所占用的内存字节数。虽然数组名本身也可以转化为一个指向首元素的指针,但其类型确实数组类型(复合类型),用sizeof 求解时不时求解地址的字节,大小而是整个数组内存的大小。而对于位于函数形参中的数组,它是一个指针类型,而不是数组类型,因此此时的sizeof是按照指针类型来求解的。


4、结构体的sizeof

三个原则:结构体变量的首地址能够被最大的对齐值所整除;结构体中每个成员相对于首地址的偏移量都是该成员自身对齐值的整数倍;结构体总大小为最大对齐值得整数倍。

所以在计算结构体的sizeof时:先计算各个成员的自身对齐值,取最大的作为结构体的对齐值;依次按顺序排放各个成员,成员存放的起始的位置应该是自身对齐值的整数倍,成员间可能存在浪费的内存空间;排放完所有成员后,整个结构体的内存字节大小必须是该结构体对齐值的整数倍,不够也补上。

一旦使用了#pragma pack(n),n为指定过的对齐值,那么需要取n与计算结构体的对齐值之中较小的那一个作为结构体的对齐值。

空结构体的大小为1.


5、联合体的sizeof

结构体在内存组织上是顺序的而联合体则是重叠式的,各成员共享一段内存,因此整个联合体的sizeof也就是其成员sizeof的最大值。

6、位域的sizeof

1).一个位域的大小可以超过一个字节,大小不要超过其声明的类型大小即可:
如:
int name:31;
2).如果相邻位域的类型相同,且其位宽之和小于等于类型的sizeof大小,则两位域放入一个字段存储:
如:
char name1 : 2;
char name2 : 6;
则这2个字段放入一个字节存储, sizeof结果为 1.
3).如果相邻位域的类型相同,且其位宽之和大于类型的sizeof大小,则第二个位段从下一个对齐开始存储:
如 :
char name1 : 5;
char name2 : 4;
则这2个字段放入两个字节存储,sizeof结果为 2.
4).如果相邻位域的类型不同,则这多个位段会存储在类型sizeof大的位段中,如果所有位段大小之和
小于等于最大类型的sizeof,则可以全部装下,否则,整个位域的存储空间会以最大类型的sizeof长度
来进行扩充 :
如 :
struct str{
char name1 :1;
int name2 :30;
char name3 :x;
};
当 x = 1时, sizeof(str) = 4;
当 x = 2时, sizeof(str) = 8;
5).如果你要使用位域,你应该很清楚每个字段的大小,从而有序的安排位域的顺序,最小化总字段空间:
如 :
struct str{ struct str{
char name1 : 4; char name1 : 4;
char name2 : 5; char name3 : 4;
char name3 : 4; char name2 : 5;
}; };
sizeof(str) = 3; sizeof(str) = 2;

四、sizeof与strlen的区别

1)sizeof是一个操作符(运算符),其结果为size_t 类型,而strlen是一个函数。

2)sizeof可以使用类型名作参数甚至是函数调用作为参数,而strlen只能使用 char* 类型作为参数且其指向的字符串必须以'\0'结尾。

3)sizeof在编译的时候计算,可以作为常量表达式;strlen在运行时计算,且计算的字符串的长度而不是内存的大小。








原创粉丝点击