一、Sizeof的说明
sizeof是C/C++语言的一种单目操作符,它不是函数。sizeof操作符返回值为其操作数的存储大小,用字节数表示。操作数可以是一个表达式或括在括号内的类型名。 sizeof的结果是size_t,它被定义为unsigned int类型。该类型保证容纳显示所建立的最大对象的字节大小。
二、Sizeof的使用
1、sizeof的使用形式:sizeof(var_name)或者sizeof var_name
2、数据类型必须用括号括起来:sizeof(int)
变量名可以不用括号括住:sizeof a
3、sizeof可以对表达式求值:sizeof(2.5+3.14),实际是sizeof(double)
4、sizeof可以对函数调用求值,实际上是对返回值类型求值
int func(char s[5]); { cout<<endl; return 1; } sizeof(func(“1234”))=4 //因为func的返回类型为int,所以相当于求sizeof(int)=4,sizeof(s)=4
5、以下情况不能用sizeof进行求值
1)不能对函数名求值
2)不能对不确定返回值的类型求值,如void
3)位域成员不可以使用sizeof求值
4)不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。
一般,在32位编译器下:
sizeof(int):4
sizeof(short):2
sizeof(long):4
sizeof(longlong):8
sizeof(float):4
sizeof(double):8
sizeof(char):1
sizeof(p):4,(p为指针)
32位系统下指针的sizeof是4字节,64位下是8字节
在不同的系统中这些值不一样。
6、sizeof与strlen()比较,在计算字符数组大小时,sizeof包含'\0',strlen()不包含'\0',strlen()遇到’\0’就会返回
7、对引用的sizeof,其实是对其所绑定的对象的sizeof
8、对于C字符串,需要牢记C/C++中一个汉字占两个字节(Linux下3个字节),且字符串尾有空字符。
9、对数组sizeof可以计算数组的总字节数,但数组作为参数传递时,退化为指针,这时候用数组名的sizeof是4个字节(数组的首地址即指针)
int a[50]; //sizeof(a)=4*50=200; 求数组所占的空间大小 int *a=new int[50];// sizeof(a)=4; a为一个指针,sizeof(a)是求指针
10、32bit系统中,int**a[3][4];sizeof(a)=48
使用伪指令#pragma pack(n),编译器将按照n个字节对齐;
使用伪指令#pragma pack(n),将取消自定字节对齐方式。
11、 sizeof的参数为结构或类时,有两点需要注意,第一、结构或者类中的静态成员不对结构或者类的大小产生影响,因为静态变量的存储位置与结构或者类的实例地址无关。
第二、没有成员变量的结构或类的大小为1,因为必须保证结构或类的每一个实例在内存中都有唯一的地址。
还有结构体或者类中有虚函数的,大小会加4个字节,因为有虚函数表的指针。
Class Test{int a;static doublec};//sizeof(Test)=4. Test *s;//sizeof(s)=4,s为一个指针。 Class test1{ };//sizeof(test1)=1;
以上情况:除了 sizeof(type)数据类型必须用(),其他sizeof a , sizeof(a) 都可以
测试Demo:
#include<iostream> #include<cstdlib> #include<string> using namespace std; struct s { charc; char b; int a; doubled; }; int fun(int); int main() { int a=3; ss1; cout<<sizeof s1<<endl; cout<<sizeof(s1)<<endl; cout<<sizeof a<<endl; cout<<sizeof(a)<<endl; cout<<sizeof(int)<<endl; cout<<sizeof(2+3.4)<<endl; //sizeof(double) cout<<sizeof 2+3.4<<endl; //sizeof(double) cout<<sizeof(fun(a))<<endl; cout<<sizeof fun(a)<<endl; cout<<sizeof 3<<endl; cout<<sizeof(3)<<endl; system("pause"); return 0; } int fun(int a) { returna; }
结果如下:
三、sizeof的注意项:
1、联合类型操作数的sizeof是其最大字节成员的字节数。
2、结构体(内存对齐):
struct {char b; double x;} a;
在32位机器上sizeof(a)=12,而一般sizeof(char)+ sizeof(double)=9。因为编译器在考虑对齐问题时,在结构中插入空位以控制各成员对象的地址对齐。如double类型的结构成员x要放在被4整除的地址。
3、如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。
四、sizeof的主要用途
1、sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。例如:
void *malloc(size_t size),
size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)。
2、sizeof的另一个的主要用途是计算数组中元素的个数。例如:
void * memset(void * s,int c,sizeof(s))。
由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用sizeof来代替常量计算。
五、 sizeof计算结构体大小:
为了提高CPU的存储速度,编译器会对一些变量的起始地址做对齐处理。在默认情况下,规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该变量的类型所占用的字节数的倍数。
各成员变量在存放的时候根据在结构中出现的顺序依次申请空间,同时按照上面的对齐方式调整位置,空缺的字节编译器会自动填充。同时为了确保结构的大小为结构的字节边界数(即该结构中占用最大空间的类型所占用的字节数)的倍数,所以在为最后一个成员变量申请空间后,还会根据需要自动填充空缺的字节。(通常是取占内存最大的变量类型的大小的整倍数)
看如下结构体:
struct MyStruct { double dda1; char dda; int type };
这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为:8+1+3+4=16,刚好为结构的字节边界数(即结构中占用最大空间的类型所占用的字节数sizeof(double)=8)的倍数,所以没有空缺的字节需要填充。所以整个结构的大小为:sizeof(MyStruct)=8+1+ 3+4=16,其中有3个字节是编译器自动填充的,没有放任何有意义的东西。
下面再举个例子,交换一下上面的MyStruct的成员变量的位置,使它变成下面的情况:
struct MyStruct { char c; double d; int a; };
sizeof(MyStruc)为24。sizeof(MyStruct)=1+7+8+4+4=24
C/C++中提供了#pragma pack(n)来设定变量以n字节对齐方式。n字节对齐就是说变量存放的起始地址的偏移量有两种情况:第一、如果n大于等于该变量所占用的字节数,那么偏移量必须满足默认的对齐方式,第二、如果n小于该变量的类型所占用的字节数,那么偏移量为n的倍数,不用满足默认的对齐方式。结构的总大小也有个约束条件,分下面两种情况:如果n大于所有成员变量类型所占用的字节数,那么结构的总大小必须为占用空间最大的变量占用的空间数的倍数;
否则必须为n的倍数。下面举例说明其用法。
#pragma pack(push) //保存对齐状态 #pragma pack(4)//设定为4字节对齐 struct test { char m1; double m4; int m3; }; #pragma pack(pop)//恢复对齐状态
以上结构的大小为16,设定的对齐方式(4字节对齐),m1占用1个字节。接着开始为m4分配空间,这时其偏移量为1,需要补足3个字节,这样使偏移量满足为n=4的倍数(因为sizeof(double)大于n),m4占用8个字节。接着为m3分配空间,这时其偏移量为12,满足为4的倍数,m3占用4个字节。这时已经为所有成员变量分配了空间,共分配了16个字节,满足为n的倍数。