Chinaunix首页 | 论坛 | 博客
  • 博客访问: 55501
  • 博文数量: 18
  • 博客积分: 2010
  • 博客等级: 大尉
  • 技术积分: 320
  • 用 户 组: 普通用户
  • 注册时间: 2008-03-03 14:07
文章分类

全部博文(18)

文章存档

2008年(18)

我的朋友

分类: C/C++

2008-04-08 11:07:12

1):SIZEOF

          1、定义:sizeofC/C++中的一个操作符(operator)是也,简单的说其作用就是返回一个对象或者类型所占的内存字节数。

          2、语法格式 sizeof有三种语法形式,如下:

             1) 用于数据类型  sizeof( type_name ); // sizeof( 类型 );

             2) 用于变量  sizeof( object ); // sizeof( 对象 );

                          sizeof object; // sizeof 对象;

            所以,

            int i;

            sizeof( i ); // ok

            sizeof i; // ok

            sizeof( int ); // ok

            sizeof int; // error

            注意:sizeof操作符不能用于函数类型,不完全类型或位字段。不完全类型指具有未知存储大小的数据类型,如未知存储大小的数组类型、未知内容的结构或联合类型、void类型等。 

  如sizeof(max)若此时变量max定义为int max(),sizeof(char_v) 若此时char_v定义为char char_v [MAX]MAX未知,sizeof(void)都不是正确形式。

 

          3sizeof操作符的结果

             sizeof操作符的结果类型是size_t,它在头文件中typedefunsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。 

 

          1)若操作数具有类型charunsigned charsigned char,其结果等于1。 

  ANSI C正式规定字符类型为1字节。 

          2intunsigned int 、short intunsigned short 、long int 、unsigned long 、 floatdoublelong double类型的sizeof 在ANSI C中没有具体规定,大小依赖于实现,一般可能分别为2222 444810。 

          3)当操作数是指针时,sizeof依赖于编译器。例如Microsoft C/C++7.0中,near类指针字节数为2farhuge类指针字节数为4。一般Unix的指针字节数为4。 

          4)当操作数具有数组类型时,其结果是数组的总字节数。 

          5)联合类型操作数的sizeof是其最大字节成员的字节数。结构类型操作数的sizeof是这种类型对象的总字节数,包括任何垫补在内。 

  让我们看如下结构: 

  struct {char b; double x;} a; 

  在某些机器上sizeofa=12,而一般sizeofchar+ sizeofdouble=9。 

  这是因为编译器在考虑对齐问题时,在结构中插入空位以控制各成员对象的地址对齐。如double类型的结构成员x要放在被4整除的地址。 

         6)如果操作数是函数中的数组形参或函数类型的形参,sizeof给出其指针的大小。

        4sizeof与其他操作符的关系 

  sizeof的优先级为2级,比/%3级运算符优先级高。它可以与其他操作符一起组成表达式。如i*sizeofint);其中iint类型变量。 

        5sizeof的主要用途 

        1sizeof操作符的一个主要用途是与存储分配和I/O系统那样的例程进行通信。例如: 

  void *mallocsize_t size, 

  size_t fread(void * ptr,size_t size,size_t nmemb,FILE * stream)。 

        2sizeof的另一个的主要用途是计算数组中元素的个数。例如: 

  void * memsetvoid * s,int c,sizeof(s))。 

        6、建议 

  由于操作数的字节数在实现时可能出现变化,建议在涉及到操作数字节大小时用sizeof来代替常量计算。 

       2sizeof用法

          假设以后的程序都是32C的程序。

          int i=10;

          在这里由于是32位的C 程序,故对于一个整型变量应该用32位来存放,

          sizeof(i)4字节;

          sizeof(int)也为4字节;

         

          char a='b';

          char b[]="hello,world";

          char c[20]="hello,world";

          char *p=b;

          明显sizeof(a)1字节;

          b为数组名sizeof是求取数组所占内存的大小,故sizeof(b)12,可能大家会注意到hello,world仅有11个字符,然而为什么要站12字节呢? 这是因为在没有指定数组大小的时,为数组初始化后会在后面加上结束符;因此为12

          因为 p指针变量是一个地址,地址信息又用32位来存放,所以sizeof(p)4;

          sizeof(*p)为数组b的大小。;

          由于在定义数组时指定了数组的大小sizeof(c)故为20,在这里hello,world仅为11字符,在后面回自动用0填充满整个数组;

         

         我们对sizeof有初步的了解了,再接下来看这样的一个结构

         struct 1{ 

            int a;

           char b;

            int c;

         } ;

        sizeof(s1)等于多少?或许你是这样想的,char1个字节,int4个字节,那么加起来就应该是9。很可能你是错的!VC6中按默认设置得到的结果为12,32C中也为12。那仔细分析一下为什么为12!

        如果是用那样来进行存储的的话,那么在读取这些变量时PC指针一会加4,而一会加1,一会又加4 PC加减没有一固定值,很明显影响系统的效率。在编译原理为了提高系统的效率采用了内存对齐技术。在后面详细分析内存对齐。

        在这里主要看一下char在这里占的空间。这里是32为的程序,故int4个字节,没有调整内存对齐的方式,故应该按照默认的方式进行内存对齐。在此结构里面应按照4个字节对齐效率最好。故char在这里占的空间也应该为4个字节。后面有3填充字节。

        在分析下面的结构

        struct s2{ 

            int a;

           char b;

            int c;

            s1  s

         } ;

         sizeof(s2)等于多少? 24字节。

         #include

         void print(char a[])

         { printf("%d\n",sizeof(a));

         }

         main()

         { char a[]="hello,world";

           print(a);

         }

         运行的结果是什么呢? 或许你会认为结果是12。在print(a)的实参仅仅将数组的地址传给形参,而不是将整个数组作为实参传递。所以既然形参接受的是一个地址,那结果应是4

        

         字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:

            1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

            2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding);

            3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

 

            对于上面的准则,有几点需要说明:

           1) 前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏移量了呢因为有了第1点存在,所以我们就可以只考虑成员的偏移量,这样思考起来简单。想想为什么。

结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也在stddef.h中定义,如下:

#define offsetof(s,m) (size_t)&(((s *)0)->m)

例如,想要获得S2c的偏移量,方法为

size_t pos = offsetof(S2, c);// pos等于4

           2) 基本类型是指前面提到的像charshortintfloatdouble这样的内置数据类型,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。

          含位域结构体的sizeof

前面已经说过,位域成员不能单独被取sizeof值,我们这里要讨论的是含有位域的结构体的sizeof,只是考虑到其特殊性而将其专门列了出来。

C99规定intunsigned intbool可以作为位域类型,但编译器几乎都对此作了扩展,允许其它类型类型的存在。使用位域的主要目的是压缩存储,其大致规则为:

          1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;

          2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;

          3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式;

          4) 如果位域字段之间穿插着非位域字段,则不进行压缩;

          5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。

 

还是让我们来看看例子。

示例:

struct BF1

{

char f1 : 3;

char f2 : 4;

char f3 : 5;

};

其内存布局为:

|_f1__|__f2__|_|____f3___|____|

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|

0 3 7 8 1316

位域类型为char,第1个字节仅能容纳下f1f2,所以f2被压缩到第1个字节中,而f3

能从下一个字节开始。因此sizeof(BF1)的结果为2

 

示例:

struct BF2

{

char f1 : 3;

short f2 : 4;

char f3 : 5;

};

由于相邻位域类型不同,在VC6中其sizeof6,在Dev-C++中为2

 

示例:

struct BF3

{

char f1 : 3;

char f2;

char f3 : 5;

};

非位域字段穿插在其中,不会产生压缩,在VC6Dev-C++中得到的大小均为3

        联合体的sizeof

结构体在内存组织上是顺序式的,联合体则是重叠式,各成员共享一段内存,所以整个联合体的sizeof也就是每个成员sizeof的最大值。结构体的成员也可以是复合类型,这里,复合类型成员是被作为整体考虑的。

所以,下面例子中,Usizeof值等于sizeof(s)

union U

{

int i;

char c;

S1 s;

}

              ---------补充----------------------------

参数为结构或类。Sizeof应用在类和结构的处理情况是相同的。但有三点需要注意:

 

第一、结构或者类中的静态成员不对结构或者类的大小产生影响,因为静态变量的存储位置与结构或者类的实例地址无关。

 

第二、没有成员变量的结构或类的大小为1,因为必须保证结构或类的每一个实例在内存中都有唯一的地址。

 

第三、类中含有虚函数的情况,虚函数表指针占用4个字节大小,并且放在类的开头。即虚函数在类中的位置对类的大小无影响,其始终是在最前面的。

 

下面举例说明,

 

1Class Test{int a;static double c};//sizeof(Test)=4.

 

2Test *s;//sizeof(s)=4,s为一个指针。

 

3Class test1{ };//sizeof(test1)=1;

 

4class   A

{

   double  a;

   char  b;

   virtual   p(){};

};//sizeof(A)=24,因为类中有虚函数,所以等价于下面:

 

class A

{

 

    [color=#FF0000]void [/color]*p; //虚函数表指针

    double a;

    char  b;

};
阅读(1038) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~