(1)
MSDN:The sizeof keyword gives the amount of storage, in bytes, associate with a variable or a type(including aggregate types). This keyword returns a value of type size_t(typedef unsigned int size_t).
语法:sizeof(object);=> sizeof(1);
(2)
你不能用sizeof(void);这样将产生:error C2070: illegal sizeof operand
比如如下代码:
void fun(){
}
int main(){
}//这个编译是不会通过的
char fun(){
}
int main()
{
}//引申一下,这个是测量返回值的长度,因此是1,而不是指针的长度4.结合第八点来看。
(3)
目前基本上所有的编译器都把指针的大小看做是4byte。其实指针也是变量,只不过这个变量很特殊,它是存放其他变量的地址的变量。又由于目前32位计算机平台上的程序段的寻址范围是4GB,寻址的最小单元是Byte,4GB等于232byte。这么多得内存起地址如何编码,只需要用32个bit就行了,而32bit=32、8=4Byte,也就是说只要4Byte就能存储这些内存的地址了。因此对任何类型的指针变量进行sizeof运算其结果就是4.(一个疑问,指针类型用4Byte只存储了指针指向的地址,如何区分是何种类型的指针呢?)
(4)
int a[10];sizeof(a); 这样可求得长度是10*4=40.(引申问题:数组名和指针的区别。参看下篇),另外注意char ch[]=”abc”; sizeof(ch);结果为4,注意字符串数组末尾有’\0’,通常我们可以利用sizeof来计算数组中包含的元素个数。其做法是:int n=sizeof(a)/sizeof(a[0]);
要注意对函数的形参数组使用sizeof的情况。如:
void fun(int arr[10]){
}//n的值为4
这里的原因是在函数参数传递时,数组被转化成指针了。加入直接传递整个数组的话,那么必然涉及到数组元素的拷贝(实参到形参的拷贝),当数组非常大时,这会导致执行效率极低!而只传递数组的地址(即指针)那么只需要拷贝4Byte。
引申:sizeof和strlen的区别:
strlen(char*)函数求的是字符串的实际长度,它求的方法是从开始遇到第一个’\0’,如果你只定义没有给它赋初值,这个结果是不定的,它从指针指向的首地址一直找下去,直到遇到’\0’为止。
char aa[10];strlen(aa);
char aa[10]={‘\0’};strlen(aa);
char aa[]=”LRP”;strlen(aa);
char*aa=”0123456789”;
sizeof(aa);
sizeof(*aa);
strlen(aa);
char aaa[]={"LRPLRP"};
int a,b;
fun(aaa,a,b);
void fun(char aaa[],int&a,int&b)
{
}
//得到的a=6,b=4.在函数内部,虽然aaa转化成指针,但是strlen还是测试aaa开始直到’\0’为止的字符串的长度,而sizeof则是测指针的长度。
(5)
例如int*a = new int[10]; int n = sizeof(a); 得到n的值是4。
(6)
假设有两个源文件:file1.cpp和file2.cpp,其中file1.cpp定义:
int arrayA[10]={1,2,3,4,5,6,7,8,9,10};
int arrayB[10]={11,12,13,14,15,16,17,18,19,20};
file2.cpp中包含如下几个语句:extern arrayA[]; extern arrayB[10];
cout<<sizeof(arrayA)<<endl;
cout<<sizeof(arrayB)<<endl;
在file1.cpp中第三条语句编译出错,而第四条语句正确。原因:sizeof(arrayA)试图求不完整数组的大小。这里的不完整的数组是指数组大小没有确定的数组。sizeof运算符的功能是求某种对象的大小,然而声明:extern int arrayA[]只是告诉编译器arrayA是一个整型数组,但是并没有告诉编译器它包含多少个元素,因此对file2.cpp中得sizeof来说它无法求出arrayA的大小,所以编译器干脆不让你编译通过。arrayB明确告诉了arrayB是一个包含10个元素的整型数组,因此大小事确定的。
(7)
char ch=1;
int num=1;
int n1=sizeof(ch+num);
int n2=sizeof(ch=ch+num);
由于默认类型转换原因,ch+num的计算结果的类型是int,因此n1的值为4.而表达式ch=ch+num的结果的类型是char,记住虽然在计算ch+num时,结果为int,但是把结果赋值给ch时又进行了类型转换,因此表达式的最终类型还是char,因此n2等于1。
对于n2=sizeof(ch=ch+num); 乍一看改程序貌似实现了让ch加上num并赋值给ch的功能,事实并非如此,由于sizeof只关心类型大小,所以它自然不应该对表达式求值。但是,int len=3; cout<<sizeof(int[++len])<<”,”<<len;输出地答案却是16,4.(原文中作者说得时在Dev C++编译器下,但是经过在VC下测试,编译不通过。后来改成int num = 3;
(8)
int fun(int &num)
{
}
int main()
{
}//输出结果4 0
sizeof(fun(num))得到的是函数返回类型的大小,而fun(num)的返回值类型是int,所以等价于sizeof(int)得到结果为4.另外不要认为这个长度为fun函数内部的局部变量所占空间的大小(认为结果为8,即a和b两个int的长度也是错误的)另外也注意,sizeof(fun(num))也不是求函数指针的大小,切记是求得返回值类型的长度大小。
这里跟特征7很类似。sizeof的操作对象是函数调用时,它不执行函数体。为此,建议大家不要把函数体放在sizeof后面的括号里,这样让人误以为函数体执行了,其实它根本没执行。另外可知:不能对返回类型是void的函数使用sizeof求其大小,如2中讲得编译报错。
另外注意sizeof(fun)的大小是多少呢?其实得不到答案,原因是编译不通过。(很多人可能认为fun是函数名,而再把函数名等价于函数的地址,地址是指针),于是得到了其值是4.但是事实却不是这样,却是编译不通过。
(9)
结构体的大小跟结构体成员对其有密切关系,而并非简单地各个成员的大小之和。比如两个结构体AA和BB。,使用sizeof分别得出结果是24和16.可以看出sizeof(AA)并不等于sizeof(int)+sizeof(double)+sizeof(int)
struct AA{ }; | struct BB{ }; |
结构体成员对齐的规则:(1)结构体大小等于结构体内最大成员大小的整数倍;(2)结构体内的成员的首地址相对于结构体首地址的偏移量是其类型大小的整数倍,比如说double型成员相对于结构体的首地址的偏移量应该是8的整数倍;(3)为了满足规则1和规则2编译器会再结构体成员之后进行字节填充。
在进行设计时,组号仔细安排结构体中各个成员的顺序。
(10)
位域:类型的大小都是以字节(byte)为基本单位的,比如sizeof(char)为1byte。但是bool类型取值只有true和false,按理只用1bit就够了,但事实上sizeof(bool)等于1.为了提供一种能对变量的存储空间进行精打细算的机制,这就是位域。简单来说在结构体成员变量后面跟上的一个冒号+一个整数,就代表位域,请仔细看以下结构体:
struct A{
}item;
该结构体试图让bool类型的变量b只占用1个bit,让ch1和ch2分别只占用4个bit,以此来达到对内存精打细算的功能。语句sizeof(item.b)和sizeof(item.ch1)等对位域成员求大小的语句均不能通过编译。其原因:sizeof以byte为单位返回操作数的大小。
对包含位域的结构体可以使用sizeof求其大小,但其求值规则比较复杂,不涉及到成员对齐,还与集体编译环境有关。
延伸:class A{};sizeof(A)的结果为1,其原因:类的实例化是在类内存中分配一块地址,每个实例在内存中得都有独一无二的地址,同样空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以其长度为1。(编译器为了区分不同的类,在类中加了一个char类型,另外,如果一个文件中有256个空类,即大于char类型表示的范围,就不能区分空类了)
特别:当sizeof求数组时:
1.一般情况下sizeof会返回数组所占用的空间,这在编译期间解析得到,编程一个常量。
函数调用因为发生在运行期间,这时编译器无法在编译期间决定数组(实参给形参表示的数组不定)的大小,不能在编译时将其转换为常数,故只能将之退化为运行期间可以处理的指针。
2.当应用于静态数组时,sizeof 返回整个数组的大小。sizeof操作符不能返回动态分配的数组或外部阵列的大小。
3.在函数参数传递时,数组被转化成指针了。加入直接传递整个数组的话,那么必然涉及到数组元素的拷贝(实参到形参的拷贝),当数组非常大时,这会导致执行效率极低!而只传递数组的地址(即指针)那么只需要拷贝4Byte。
记住一点,sizeof运算符只在编译期间可见,编译结束后就没有sizeof行为了,都变为常数了(例如对形参数组做sizeof等于对指针做sizeof,变为4)。