c语言 sizeof详解

来源:互联网 发布:mac相簿照片如何导出 编辑:程序博客网 时间:2024/06/08 14:06

sizeof的概念  

  sizeof是C语言的一种单目操作符,如C语言的其他操作符++、--等。
    它并不是函数。
    sizeof操作符以字节形式给出了其操作数的存储大小。
    操作数可以是一个表达式或括在括号内的类型名。
    操作数的存储大小由操作数的类型决定。 

sizeof的使用方法  

  1、用于数据类型    
  sizeof使用形式: sizeof(type)
  数据类型必须用括号括住: sizeof(int)

  2、用于变量    
  sizeof使用形式: sizeof(var_name) 或 sizeof var_name    
  变量名可以不用括号括住.如sizeof (var_name),sizeof var_name等都是正确形式
    带括号的用法更普遍,大多数程序员采用这种形式。    
  注意:sizeof操作符不能用于函数类型,不完全类型或位字段。
     不完全类型指具有未知存储大小的数据类型,
     如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。    
    例如: sizeof(max)     
--
若此时变量max定义为int max();
      sizeof(char_v)    --若此时char_v定义为char char_v[MAX]且MAX未知,
      sizeof(void)      
     以上都是不正确形式。

sizeof的结果

  1、ANSI C正式规定字符类型为1字节。    
    sizeof(char)= 1;
    sizeof(unsigned char) = 1;
    sizeof(signed char)= 1;
  
  2、其他类型在ANSI C中没有具体规定,大小依赖于实现。
    sizeof(int)= 4;
    sizeof(unsigned int)= 4;
    sizeof(short int)= 2;
    sizeof(unsigned short) = 2;
    sizeof(long int)= 4;
    sizeof(unsigned long)= 4;
    sizeof(float)= 4;
    sizeof(double)= 8;
    sizeof(long double)= 12; //gcc 32-bit 编译器
    sizeof(long double)= 16; //gcc 64-bit 编译器

  3、当操作数是指针时,sizeof依赖于编译器。
    学过数据结构的你应该知道指针是一个很重要的概念,它记录了另一个对象的地址。既然是来存放地址的,那么它当然等于计算机内部地址总线的宽度。所以在32位计算机中,一个指针变量的返回值必定是4(注意结果是以字节为单位),在64位系统中指针变量的sizeof结果为8。
       例如: char *p;      
           sizeof(p) = 4;//gcc 32-bit 编译器
           sizeof(p) = 8;//gcc 64-bit 编译器     
 
  4、当操作数具有数组类型时,其结果是数组的总字节数。
    例如: char a[5];
        int  b[5];
        sizeof(a) = 5;
        sizeof(b) = 20;
   
  5、当操作数是具体的字符串或者数值时,会根据具体的类型进行相应转化。
      例如: sizeof(8)    = 4;  //自动转化为int类型
          sizeof(8.8)  = 8;  //自动转化为double类型,注意,不是float类型
          sizeof("ab") = 3   //自动转化为数组类型,
                                   
  6、当操作数是联合类型时,sizeof是其最大字节成员的字节数。当操作数是结构类型时,sizeof是其成员类型的总字节数,包括补充字节在内。还是拿例子来说话:
   union u{             //对union来说
       char c;
       double d;
     }u;
    sizeof(u) = max(sizeof(c),sizeof(d)) = sizeof(1,8) = 8;
  struct a{             //对struct来说
       char b; 
       double x;
    }a;   
   sizeof(a) = 16;  而一般sizeof(char) + sizeof(double) = 9; 
  这是因为编译器在考虑对齐问题时,在结构中插入空位以控制各成员对象的地址对齐。但如果全对齐的话,sizeof(a) = 16, 这是因为b被放到偏移量为0的地址,占1个字节;在存放x时,double类型长度为8,需要放到能被8整除的偏移量上,这时候需要补7个空字节, 达到8个,这时候偏移量为8,放上x后长度为16。

struct S1 {char c;double d;};union  u {            //对union来说char c;double d;} u;int a;char b;short c;double d;float f;int *p;char a1[]="abcd";int a2[3];printf("int=%d\n",sizeof(a));printf("char=%d\n",sizeof(b));printf("short=%d\n",sizeof(c));printf("double=%d\n",sizeof(d));printf("float=%d\n",sizeof(f));printf("指针=%d\n",sizeof(p));printf("数组=%d\n",sizeof(a1));printf("数组=%d\n",sizeof("ab"));printf("结构体=%d\n",sizeof(S1));printf("联合类型=%d\n",sizeof(u));
gcc 64-bit 编译器,指针=8;
gcc 32-bit 编译器,指针=4


类的sizeof

面试中遇到面试官让我求一个类的sizeof,里边有各种类型的变量,还有虚函数(但是不懂什么是虚函数)。如果有虚函数就要加上一个指向虚表的指针,4字节大小(32 位 编译器),64位编译器是8字节大小。
1、空类
class A{}; sizeof(A)=1;
求sizeof的结果是1,因为即使是没有成员之类的,一个类存在,至少都要给他一个空间,不然就没有存在的意义了。
2、简单的类
class A{int a;    double b;};
本来sizeof(A.a)+sizeof(A.b)=12;结果=16,说明类的大小也遵守类似struct字节对齐的补齐规则,补齐为double类型8字节,所有为16
3、含虚函数的类
class A{int a;virtual  fun();};
//sizeof(A)=8+8=16   (gcc-64bit编译器,指针大小为8字节)+补齐规则
//sizeof(A)=4+4=8   (gcc-32bit编译器,指针大小为4字节)

3、子类继承父类,含虚函数
class Base{public:Base();                virtual ~Base();         //每个实例都有虚函数表void set_num(int num)    //普通成员函数,为各实例公有,不归入sizeof统计{a=num;}private:    int  a;                  //占4字节    char *p;                 //4字节指针};class Derive:public Base{public:Derive():Base(){};     ~Derive(){};private:static int st;         //非实例独占   int  d;                     //占4字节   char *p;                    //4字节指针};
gcc-32bit编译器
sizeof(Base)=12;
sizeof(Derive)=20
sizeof(Derive)=sizeof(Base)+sizeof(Derive.d)+sizeof(Derive.p) 的指针即可;
gcc-64bit编译器
sizeof(Base)=24; //补齐规则
sizeof(Derive)=40
sizeof(Derive)=sizeof(Base)+sizeof(Derive.d)+sizeof(Derive.p)
因为普通继承,子类和父类的虚函数存放在同一个虚表中,所以,只需要存一个指向虚表
4.子类虚继承、父类含虚函数
class Base{public:Base();                virtual ~Base();         //每个实例都有虚函数表void set_num(int num)    //普通成员函数,为各实例公有,不归入sizeof统计{a=num;}private:    int  a;                  //占4字节    char *p;                 //4字节指针};class Derive:virtual public Base{public:Derive():Base(){};     ~Derive(){};private:static int st;         //非实例独占   int  d;                     //占4字节   char *p;                    //4字节指针};

sizeof(Derive)=sizeof(Base)+虚函数指针(指示父类存放空间的起始偏移量)+sizeof(Derive.d)+sizeof(Derive.p)
虚继承时,父类和子类的虚函数表分开放,所以,分别存储两个指向对应续表的指针,因而不用减去sizeof(A)中续表指针的大小。

类的sizeof总结:
1.类的大小为类的非静态成员数据类型大小之和,也就是说静态成员数据不作考虑
2.普通成员函数与sizeof无关
3.虚函数由于要维护在虚函数表,所以要占据一个指针大小字节
4.类的总大小也遵守类似struct字节对齐的,调整规则。


参考:http://blog.csdn.net/hairetz/article/details/4171769
http://blog.sina.com.cn/s/blog_728161840100u2ib.html


0 0
原创粉丝点击