sizeof的用法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
全面解析sizeof的用法
以下代码使用平台是Windows7 64bits+VS2012。
sizeof是C/C++中的一个操作符(operator),其作用就是返回一个对象或者类型所占的内存字节数,使用频繁,有必须对齐有个全面的了解。
1.Sizeof的基本语法
sizeof有三种语法形式,如下:
(1)sizeof( object ); // sizeof( 对象);
(2)sizeof( type_name ); // sizeof( 类型);
(3)sizeof object; // sizeof 对象;
第三种语法结构虽然正确,为简单统一,均使用一、二中写法。
例如:
int i;
sizeof( i ); // ok
sizeof i; // ok
sizeof( int ); // ok
sizeof int; // error
2.sizeof计算基本类型与表示式
sizeof计算对象的大小也是转换成对对象类型的计算,也就是说,同种类型的不同对象其sizeof值都是一致的。这里,对象可以进一步延伸至表达式,即sizeof可以对一个表达式求值,编译器根据表达式的最终结果类型来确定大小,sizeof是编译时进行运算,与运行时无关,不会对表达式进行计算。
考察如下代码:
#include
using namespace std;
int main(int argc,char* argv[])
{
cout<<"sizeof(char)="< cout<<"sizeof(short)="< cout<<"sizeof(int)="< cout<<"sizeof(long)="< cout<<"sizeof(long long)="< cout<<"sizeof(float)="< cout<<"sizeof(double)="< int i=8; cout<<"i="< cout<<"sizeof(i)="< cout<<"sizeof(i)="< cout<<"i="< } 在64bits的Windows下运行结果是 sizeof(char)=1 sizeof(short)=2 sizeof(int)=4 sizeof(long)=4 sizeof(long long)=4 sizeof(float)=4 sizeof(double)=8 i=8 sizeof(i)=4 sizeof(i)=4 i=8 注意两点, 第一:i的值并未发生改变,表明sizeof括号内的表达式并没有执行,sizeof在编译时求其表达式的运算结果的类型,sizeof运算与运行时无关。sizeof(i)等价于sizeof(int),sizeof(i=5)等价于sizeof(int),也就是说在可执行代码中,并不包含i=5这个表达式,它早在编译阶段就被处理了。 第二:long int是否占8字节,与编译器的实现有关,Visual C++在VS2012中使用的编译器是cl.exe,在64bits的Windows下仍然将long编译为4字节,要想使用8字节长整型,保险起见,使用long long型。 3.sizeof计算结构体 sizeof作用于基本数据类型,在特定的平台和特定的编译中,结果是确定的,如果使用sizeof 计算结构体的大小,情况稍微复杂一下。考察如下程序 struct S1 { char c; int i; }; cout<<”sizeof(S1)=”< sizeof(S1)结果是8,并不是想象中的sizeof(char)+sizeof(int)=5。这是因为结构体或者类成员变量具有不同类型时,需要进程成员变量的对齐,计算机组成原理中说明,对齐的目的是减少访存指令周期,提高CPU存储速度。 3.1内存对齐的原则 1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除; 2) 结构体每个成员相对于结构体首地址的偏移量都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节; 3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节。 有了以上三个内存对齐的原则,就可以轻松应对嵌套结构体类型的内存对齐。如下:struct S2 { char c1; S1 s; char c2 }; 在寻找S2的最宽基本数据类型时,包括其嵌套的结构体中的成员,从S1中寻找出最宽结构体数据类型是int,因此S2的最宽数据类型是int。S1 s在结构体S2中的对齐也是按前面三个准则进行,因此sizeof(S2)=sizeof(char)+pad(3)+sizeof(S1)+1+pad(3)=1+3+8+1+3=16字节,其中pad(3)表示填充3个字节。 结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也在stddef.h中定义,如下: #define offsetof(s,m) (size_t)&(((s *)0)->m) 例如,想要获得S2中c的偏移量,方法为 size_t pos = offsetof(S2, c); // pos等于4 3.2预处理编译器指导指令#pragma pack #pragma pack( n ),n为字节对齐数,其取值为1、2、4、8、16,默认是8,表明最宽数据类型不超过8。如果这个值比结构体成员的sizeof值小,那么该成员的偏移量应该以此值为准,即是说,结构体成员的偏移量应该取二者的最小值,公式如下: offsetof( item ) = min( n, sizeof( item ) )。 考察如下代码: #pragma pack(push) // 将当前pack设置压栈保存 #pragma pack(2) // 必须在结构体定义之前使用 struct S1 { char c; int i; }; struct S2 { char c1; S1 s; char c2 }; #pragma pack(pop) // 恢复先前的pack设置 因此,sizeof(S2)=sizeof(char)+pad(1)+sizeof(S1)+1+pad(1)=1+1+6+1=10字节。 3.3空结构体 C/C++中不允许长度为0的数据类型存在。对于“空结构体”(不含数据成员)的大小不为0,而是1。“空结构体”变量也得被存储,这样编译器也就只能为其分配一个字节的空间用于占位了。如下: struct S3 { }; sizeof( S3 ); // 结果为1 3.4 位域结构体 有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态,用一位二进位即可。为了节省存储空间,