sizeof 用法分析

来源:互联网 发布:给排水画图软件 编辑:程序博客网 时间:2024/05/24 00:19

转自 http://gaoce19871026.blog.163.com/blog/static/11696126201051305834797/

sizeof的用法(一)

1. 基本类型:

不同系统或者不同编译器得到的结果可能是不同的。例如int类型在16位系统中占2个字节,在32位系统中占4个字节。如在XP中测试结果如下:
   sizeof(bool)=1;
   sizeof(char)=1;
   sizeof(short)=2;
   sizeof(long)=4;
   sizeof(int)=4;
   sizeof(float)=4;
   sizeof(double)=8;
   sizeof(string)=16;
   sizeof(vector<elemType>)=16;
   元素类型为T,个数为n的数组array:sizeof(array)=n*sizeof(T);

  
       2. 数组、指针和引用:

 int a[50];  //sizeof(a)=4*50=200; 求数组所占的空间大小

 int *a=new int[50];// sizeof(a)=4; a为一个指针,sizeof(a)是求指针的大小,在32位系统中占4个字节。
      注:sizeof作用于指针变量时,结果总是为4,而作用于引用变量时,结果等于所引用的变量的size。

 如:double a; double* b=&a; double& c=a;
      则sizeof(b)=4;sizeof(c)=8。
  

3. 结构和类:

 Sizeof应用在类和结构的处理情况是相同的。但有两点需要注意,第一、结构或者类中的静态成员不对结构或者类的大小产生影响,因为静态变量的存储位置与结构或者类的实例地址无关。第二、没有成员变量的结构或类的大小为1,因为必须保证结构或类的每一个实例在内存中都有唯一的地址。


     1)无父类的类 : 其size原则上等于其非静态成员变量的size之和:
     class CTest1

     {
          public:
               int a,b
               static double c;
               double d;
         };
   sizeof(CTest1)=sizeof(a)+sizeof(b) +sizeof(d)=4+4+8=16;
  为什么说原则上等于呢?因为变量只能在内存中一个字的开头存储,所以定义成员变量的顺序可能会影响到类的size,如将上面的CTest1改为:
   class CTest2

   {
         public:
             int a;
             static double c;
             double d;
              int b;
        };
    sizeof(CTest2)=8+8+8=24; 可以看出类中成员变量的定义顺序会影响到内存的利用率,这是跟编译器的对齐方式有关。
     2)派生类:需要加上其基类的size
  class CTest3:CTest1

  {
       public:
            int e;
      };

    sizeof(CTest3)=24(仍然会自动补齐16+8)
      3)空类:

     class CTest4{}; //sizeof(CTest4)=1

 

     class CTest5
              {
                 CTest5(){}
                 CTest5(int a,int b=0){}
                 double fun(){}
                };  //sizeof(CTest5)=1

    class CTest6{virtual ~CTest5(){}};//sizeof(CTest6)=4  (虚函数会分配一个指针,所以一旦包含虚函数就为4)

 

 

4.参数为其他。下面举例说明:

   int func(char s[5]);

   {

     cout<<sizeof(s);//这里将输出4,本来s为一个数组,但由于做为函数的参数在传递的时候系统处理为   一个指针,所 以sizeof(s)实际上为求指针的大小。

     return 1;

}

    sizeof(func("1234"))=4//因为func的返回类型为int,所以相当于求sizeof(int).

 

  几个小陷阱:

1.  使用sizeof时string的注意事项:
             string sss="hello";
             sizeof(sss)=16  sizeof(sss.c_str())=4   strlen(sss.c_str())=5 

              sizeof(s)等于string类的大小,sizeof(s.c_str())得到的是字符串指针长度。

 2.   cout<<sizeof(1==2)<<endl;

       == 操作符返回bool类型,相当于 cout<<sizeof(bool)结果为1,但不同编译器结果会有所不同,vc中测试结果为4

 3.   cout<<sizeof(unsigned int)<<endl;  //4

       unsigned影响的只是最高位bit的意义,数据长度不会被改变的。

 4.   int a = 0;
               cout<<sizeof(a=3)<<endl;   //4
               cout<<a<<endl;     //0

 输出为什么是4,0而不是期望中的4,3???就在于sizeof在编译阶段处理的特性。由于sizeof不能被编译成机器码,所以sizeof作用范围内,也就是()里面的内容也不能被编译,而是被替换成类型。=操作符返回左操作数的类型,所以a=3相当于int,而代码也被替换为: 
        int a = 0;
        cout<<4<<endl;
        cout<<a<<endl;

结论:不要把sizeof当成函数,也不要看作一元操作符,把他当成一个特殊的编译预处理。

 

[补充]:C++中sizeof与strlen函数的区别

    1. sizeof 操作符的结果类型size_t,它在头文件中typedef为unsigned int类型: typedef unsigned int size_t.

    2. sizeof是是长度运算符,获得数据类型或是变量的长度,如果是数据类型,则返回数据类型大小,如果是用数组,则返回数组所占空间大小,strlen是计算字符串长度的函数,返回的是实际串长度,以char* 作参数,且必须是以'/0'结尾。

    3. sizeof在编译的时候就计算出来了,strlen的结果要在运行的时候才能计算出来。

    4. 数组做长度运算符sizeof的参数不退化。数组做函数strlen的参数就退化为指针了,因为数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址。

 


       char* ss = "0123456789";  
       cout<<sizeof(ss)<<endl;   //4  
       cout<<sizeof(*ss)<<endl;  //1  
       cout<<strlen(ss)<<endl;   //10  
 
       char ss1[] =  "0123456789";  
       cout<<sizeof(ss1)<<endl;  //11  
       cout<<sizeof(*ss1)<<endl;  //1  
       cout<<strlen(ss1)<<endl;  //10  
 
       char ss2[100] =  "0123456789";  
       cout<<sizeof(ss2)<<endl;  //100*1=100
 
       char ss3[] = "0123456789/n";  
       cout<<sizeof(ss3)<<" "<<strlen(ss3)<<endl;    //12  11   /n都是按一个字符计算的,加上‘/’都按一个转义字符计算(/n,/t,/a....),即为1位

char ss4[] = "0123456789/n/t/0"; 
       cout<<sizeof(ss4)<<" "<<strlen(ss4)<<endl;      //15  13  strlen遇到‘/0’结束

 

char ss5[] = "0123456789/n"; 
       cout<<sizeof(ss5)<<" "<<strlen(ss5)<<endl;    //13  12

 

char p[]="a/m%23";
       cout<<sizeof(p)<<" "<<strlen(p)<<endl;    //6  5
 
       int n[4] = {1,2,3,4};  
       cout<<sizeof(n)<<endl;   //4*4=16  


       int arr[]={1,2,3,4,5};
       cout<<sizeof(arr)<<endl;   //4*5=20


       int n1= 1234;  
       cout<<sizeof(n1)<<endl;  //4 

 

char c[2][3] = {"aa", "bb"};
       cout<<sizeof(c)<<endl;      //6
 
       int arr[4][5];
       cout<<sizeof(arr)<<endl;    //80

 

经典问题(感觉不好懂啊): 
      double* (*a)[3][6]; 
      cout<<sizeof(a)<<endl; // 4 
      cout<<sizeof(*a)<<endl; // 72 
      cout<<sizeof(**a)<<endl; // 24 
      cout<<sizeof(***a)<<endl; // 4 
      cout<<sizeof(****a)<<endl; // 8 
      a是一个很奇怪的定义,表示一个指向double*[3][6]类型数组的指针。既然是指针,所以sizeof(a)就是4。
      既然a是执行double*[3][6]类型的指针,*a就表示一个double*[3][6]的多维数组类型,因此sizeof(*a)
      =3*6*sizeof(double*)=72。同样的,**a表示一个double*[6]类型的数组,所以sizeof(**a)=6*sizeof  (double*)=24。***a就表示其中的一个元素,也就是double*了,所以sizeof(***a)=4。至于****a,就是一个double了,所以sizeof(****a)=sizeof(double)=8。 

 

 

sizeof的用法(二)

一、由几个例子说开去

第一个例子:

char* ss = "0123456789";
       sizeof(ss) 结果 4 ===》ss是指向字符串常量的字符指针
       sizeof(*ss) 结果 1 ===》*ss是第一个字符

char ss[] = "0123456789";
       sizeof(ss) 结果 11 ===》ss是数组,计算到/0位置,因此是10+1
       sizeof(*ss) 结果 1 ===》*ss是第一个字符

char ss[100] = "0123456789";
       sizeof(ss) 结果是100 ===》ss表示在内存中的大小 100×1
       strlen(ss) 结果是10 ===》strlen是个函数内部实现是用一个循环计算到/0为止之前

int ss[100] = "0123456789";
       sizeof(ss) 结果 400 ===》ss表示再内存中的大小 100×4
       strlen(ss) 错误 ===》strlen的参数只能是char* 且必须是以''/0''结尾的

char q[]="abc";
       char p[]="a/n";
       sizeof(q),sizeof(p),strlen(q),strlen(p);
       结果是 4 3 3 2     

 

第二个例子:

class X
       {
          int i;
          int j;
          char k;
        };
        X x;
       cout<<sizeof(X)<<endl; 结果 12 ===》内存补齐 4+4+1+3=12

cout<<sizeof(x)<<endl; 结果 12 同上


        第三个例子:

char szPath[MAX_PATH]
  如果在函数内这样定义,那么sizeof(szPath)将会是MAX_PATH,但是将szPath作为虚参声明时(void fun(char szPath[MAX_PATH])),sizeof(szPath)却会是4(指针大小)

二、sizeof深入理解。


1.sizeof是运算符,strlen是函数。
2.sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''/0''结尾的。sizeof还可以用函数做参数,比如:
              short f();
               printf("%d/n", sizeof(f()));
              输出的结果是sizeof(short),即2。
3.sizeof后如果是类型必须加括弧,如果是变量名可以不加括弧。这是因为sizeof是个操作符不是个函数。
4.当适用了于一个结构类型时或变量, sizeof 返回实际的大小, 当适用一静态地空间数组, sizeof 归还全部数组的尺 寸。 sizeof 操作符不能返回动态地被分派了的数组或外部的数组的尺寸
5.数组作为参数传给函数时传的是指针而不是数组,传递的是数组的首地址,如:
fun(char [8])
fun(char [])
都等价于 fun(char *) 在C++里传递数组永远都是传递指向数组首元素的指针,编译器不知道数组的大小如果想在函数内知道数组的大小,需要这样做:进入函数后用memcpy拷贝出来,长度由另一个形参传进去
fun(unsiged char *p1, int len)
{
  unsigned char* buf = new unsigned char[len+1]
  memcpy(buf, p1, len);
}
有关内容见: C++ PRIMER?
6.计算结构变量的大小就必须讨论数据对齐问题。为了CPU存取的速度最快(这同CPU取数操作有关,详细的介绍可以参考一些计算机原理方面的书),C++在处理数据时经常把结构变量中的成员的大小按照4或8的倍数计算,这就叫数据对齐(data alignment)。这样做可能会浪费一些内存,但理论上速度快了。当然这样的设置会在读写一些别的应用程序生成的数据文件或交换数据时带来不便。MS VC++中的对齐设定,有时候sizeof得到的与实际不等。一般在VC++中加上#pragma pack(n)的设定即可.或者如果要按字节存储,而不进行数据对齐,可以在Options对话框中修改Advanced compiler页中的Data alignment为按字节对齐。
7.sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。如sizeof(max)若此时变量max定义为int max(),sizeof(char_v) 若此时char_v定义为char char_v [MAX]且MAX未知,sizeof(void)都不是正确形式


三、结束语

sizeof使用场合:

1.sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。例如: 
  void *malloc(size_t size), 
  size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)。
       2.用它可以看看一类型的对象在内存中所占的单元字节。
          void * memset(void * s,int c,sizeof(s))
       3.在动态分配一对象时,可以让系统知道要分配多少内存。
       4.便于一些类型的扩充,在windows中就有很多结构内型就有一个专用的字段是用来放该类型的字节大小。
       5.由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用sizeof来代替常量计算。
       6.如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。

 

原创粉丝点击