sizeof是一个单目运算符,不是函数,sizeof操作符以字节形式给出了其操作数在内存中的存储大小。操作数可以是一个表达式或者括在括号里内的类型名,且会忽略在括号内的各种运算。如sizeof(a++) 中的++ 不会执行。
struct 空间计算比较复杂,一般遵循两个原则:
1)整体空间是占用空间最大的成员(的类型)所占的字节数的整数倍,但是在32位linux+gcc环境下,若最大成员类型 所占的字节数超过了4,如double是8,则整体空间是4的整数倍即可。
2)数据对齐原则-----内存按结构体成员的先后顺序排列,当排列到该成员变量时,其前面已经摆放的空间大小必须是该成员类型大小的整数倍,如果不够则补齐,一次向后类推。但在linux+gcc环境下,若某个类型所占的字节数超过了4,如double为8,则前面已经摆放的空间大小是4的整数倍即可,不够则补齐。
当结构体中嵌套有其他结构体时,则上面两个原则要修改为以下两条:
1)整体空间是子结构体与父结构体中占用空间最大的成员(的类型)所占字节数的整数倍,但在linux+gcc环境下,若最大成员类型所占的字节数超过了4,如double是8,则整体空间是4的整数倍即可。
2) 数据对齐原则------父结构体内按照结构体成员的先后顺序排列,当排列到子结构体时,其前面已经排好的空间大小必须是子结构体成员中最大类型大小的整数倍,如果不够,则补齐,依次类推。但是在linux+gcc环境下,若某成员类型占据的字节数大于4,如double是8,则前面已经摆放的空间大小是4的整数倍即可,不够则补齐。
==》含数组的结构体的空间计算:结构体中,数组是按照单个变量一个一个进行摆放的,而不是视为一个整体。
C与C++允许指定占用特定位数的结构成员,字段的类型应为整型或者枚举型 ,接下来是冒号:,然后后面跟一个数字,它指定了使用的位数,且可以使用没有名字的字段来提供间距。每个成员都被称为位字段(bit field)。例:
1 struct reg
2 {
3 unsigned int SN:4;
4 unsigned int :4;
5 bool good: 4;
6 };
==》含位域结构体的空间计算:位域成员不能单独被sizeof取值,但是可以用sizeof获取含有位域的结构体大小。
使用位域的主要目的是压缩存储,大致规则为:
1)如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段紧邻前一个字段存储,直到不能容纳为止。vs2010环境下,一个inta:4,如果后面不是位域,则占用4个字节,而在Dev-c++以及linux+gcc环境下,不论位于为何种类型,所占字节数以其时间占用的字节数为准,以方便后续结构体成员的摆放,即int:4,如果后面不是位域,仅占1个字节。
2)如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则其后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍。
3)如果相邻位域的字段类型不同,则各编译器的具体实现有差异,VC6采取不压缩,Dev-c++与linux+gcc采取压缩方式。
4)如果位域字段之间穿插着非位域字段,则不进行压缩。
5)整个结构体的总大小为最宽基本类型成员大小的整数倍。
==》使用"#pragma pack "时结构体空间的计算
- #pragma pack(n) 编译器将按照n个字节对齐
- #pragma pack() 取消自定义字节对齐方式。
注意,如果结构体成员中最大的成员类型大小都小于n,则n失效,即按照结构体中最大类型成员的大小进行对齐,反之,则以n对齐。
offsetof(item) = min( n , sizeof( item ) )
#pragma pack(push) 将当前pack设置压栈保存
#pragma pack(pop) 恢复先前的pack设置
==》空结构体的大小为 1
==》enum枚举的空间计算
enum只是定义了一个常量集合,里面没有“元素",而枚举类型是当做int类型存储的,故枚举类型的sizeof值都为4.
enum day {morning , moon , aftermoon} today;
sizeof (day) = 4 ,sizeof (today ) = 4;
string name;
name.size() 计算的是长度,不包含里面的'\n';
==》函数以及类型重定义不占字节。
实例:
1. sizeof 计算结构体的大小
1.1 常见结构体
struct node{
int a;
int b;
}
sizeof(node)=8, a(4)+b(4) = 8;因为32位机器上int占4字节,所以2个int的结构体占8字节;
1.2 混合结构
struct node{
char a;
int b;
}
sizeof(node)=8, a(4)+{b(1)+(3)} = 8;因为虽然int占4字节,char占1字节。编译器为了读取效率自动做了填充做内存对齐;
struct node{
int a;
char b;
char c;
int d;
char e;
}
sizeof(node)=16; a(4)+{b(1)+c(1)+2}+{d(4)+e(1)+3} = 16;
这就引入了一个概念,叫做“内存对齐”。所谓的内存对齐,是指一种计算机体系结构(如X86)对基本数据类型的存储位置有限制,要求其地址为某个数的倍数,通常这个数为4或8。编译器为了效率,在相邻的变量之间放置了一些填充字节来保证数据的对齐.至于为什么会有这样的设计,简单的说访存总线的位数固定,以32位总线为例,地址总线的地址总是4对齐的,所以数据也四对齐的话,一个周期内就可以把数据读出。
1.2 不同编译器计算法不同
struct node{
double a;
int b;
int c;
char d;
}
同样X86架构上:vc编译后sizeof(node)=24;linux gcc 编译后 sizeof(node)=20;因为:在VC中规定, 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;而在gcc中规定对齐模数最大只能是4,也就是说,即使结构体中有double类型,对齐模数还是4,所以数据是按照1,2,4对齐的。所以:
vc下 :sizeof(node)=a(8)+b(4)+c(4)+{d(1)+7} = 24;
linux gcc下: sizeof(node)= a(4)+a(4)+b(4)+c(4)+{d(1)+3} = 20;