sizeof总结

来源:互联网 发布:百度网盘 for linux 编辑:程序博客网 时间:2024/05/18 20:04

/***************************************************************************************************
                            sizeof 总结
编    者:张永辉 2012年9月17日
***************************************************************************************************/
c语言中判断数据类型长度符 sizeof
  用法
        1) sizeof(类型说明符,数组名或表达式);
        2) sizeof 变量名

    1. 定义:

        sizeof是一个操作符,返回(unsigned int size_t)一个对象或者类型所占的内存字节数。
        sizeof( char、signed char unsigned char ) == 1

    2. 语法:

        sizeof有三种语法形式
            1) sizeof( object );            // sizeof( 对象 );
            2) sizeof( type_name );         // sizeof( 类型 );
            3) sizeof object;               // sizeof 对象;

        例如:
            sizeof( 2 );        == sizeof( int );
            sizeof( 2 + 3.14 ); == sizeof( double );

            char foo(void);
            sizeof( foo() );    == sizeof( char );  //其结果是函数返回类型的大小,函数并不会被调用

            C99标准规定,函数、不能确定类型的表达式以及位域(bit-field)成员不能被计算sizeof值,即下面这些写法都是错的
            sizeof( foo );          // error

            void foo2() { }
            sizeof( foo2() );       // error
            struct S
            {
                unsigned int f1 : 1;
            };
            sizeof( S.f1 );         // error


  3. sizeof的常量性

        sizeof的计算发生在编译时刻,所以它可以被当作常量表达式使用,如:
            char ary[ sizeof( int ) * 10 ]; // ok

        最新的C99标准规定sizeof也可以在运行时刻进行计算,如下面的程序在Dev-C++中可以正确执行:(但在没有完全实现C99标准的编译器中就行不通了)
            int n = 10;                     // n动态赋值
            char ary[n];                    // C99也支持数组的动态定义
            printf("%d\n", sizeof(ary));    // ok. 输出10

  4. 基本数据类型的sizeof

        short、int、long、float、double由于和系统相关的,所以可能不同,可能会在程序移植造成麻烦。
        一般的,在32位编译环境中,sizeof(int)的取值为4。

  5. 指针变量的sizeof

        指针,它记录了另一个对象的地址。那么它当然等于计算机内部地址总线的宽度。
            所以在32位计算机中,指针变量的sizeof是4,64位系统的sizeof为8.

        指针变量的sizeof值与指针所指的对象没有任何关系.
            char* pc = "abc";           sizeof( pc );   // 结果为4
            int* pi;                    sizeof( pi );   // 结果为4
            string* ps;                 sizeof( ps );   // 结果为4
            char** ppc = &pc;           sizeof( ppc );  // 结果为4
            void (*pf)();               sizeof( pf );   // 结果为4

  6. 数组的sizeof

        数组的sizeof值等于数组所占用的内存字节数,如:
            char a1[] = "abc";  // 结果为4,一个NULL终止符
            int a2[3];          // 结果为3*4=12(依赖于int)

        求数组元素的个数
            int c1 = sizeof( a1 ) / sizeof( int );      // 总长度/单个元素的长度
            int c2 = sizeof( a1 ) / sizeof( a1[0] );    // 总长度/第一个元素的长度

        写到这里,提一下:
            void foo3(char a2[3])           //没有分配一个数组
            {  int c2 = sizeof( a2 );  }   // c2 == 4, 蜕变成指针

  7. 结构体的sizeof

        重要话题:字节对齐
            原因:字节对齐有助于加快计算机的取数速度,否则就得多花指令周期了。
                为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),
                    让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,
                    让宽度为4的基本数据类型(int等  )都位于能被4整除的地址上,以此类推。
                这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。

        一个结构体示例:
            struct S1
            {
                char c;
                int i;
            };              VC6中sizeof(S1) == 8。

            struct S2       交换位置
            {
                int i;
                char c;     sizeof(S1) == 8 //此后面有3个填充字节
            };

            struct S3       sizeof(S3) == 8
            {
                int i;
                char c;     offsetof(S3, c)  == 4   相对首地址的偏移
                char cc;    offsetof(Sd, cc) == 5
            };


        字节对齐的细节和编译器实现相关,但一般满足三个准则:
            1) 结构体变量的首地址能够被其 ‘最宽基本类型成员’大小所整除;
            2) 每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,
            3) 结构体的总大小为结构体‘最宽基本类型成员’大小的整数倍。

        对于上面的准则,有几点需要说明:
            1)某个成员相的地址偏移量可以通过宏offsetof()来获得,stddef.h中定义如下:
                #define offsetof(s,m) (size_t)&(((s *)0)->m)
            2)基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型
              “数据宽度”就是指其sizeof的大小。
            3)当是复合类型时,最宽基本类型在其子成员中找,而不是把复合成员看成是一个整体。
              在确定复合类型成员的偏移位置时则是将复合类型作为整体看待。

            示例:
                struct S3
                {
                    char c1;        c1的偏移量为0 ,占0-4   其大小为4,填充3个字节
                    S1 s;           s 的偏移量为4 ,占5-12  其大小为8, 无填充
                    char c2;        c2的偏移量为12,占13-13 其大小为8, 填充3字节
                };

                S1的最宽简单类型为int,
                S3的最宽简单类型为int,(将S1“打散”看的)。
                sizeof(S3)==16。

        编译器的pack指令对sizeof的影响
            它是用来调整结构体对齐方式的,VC6中通过#pragma pack实现,也可以直接修改/Zp编译开关。
            #pragma pack的基本用法为:#pragma pack(n),其取值为1、2、4、8、16,默认是8
                结构体成员的偏移 offsetof( .item ) = min(   n, sizeof( .item ) )

            示例:
                #pragma pack(push)  // 将当前pack设置压栈保存
                #pragma pack(2)     // 必须在结构体定义之前使用

                    struct S1
                    {
                        char c;
                        int i;      min(2, sizeof(i))==2,所以i的偏移量==2,
                    };              sizeof(S1)==6

                    struct S3
                    {
                        char c1;    c1的偏移量为0 ,占0-1   其大小为2,填充1个字节
                        S1 s;       s 的偏移量为2 ,占2-7   其大小为6, 无填充
                        char c2;    c2的偏移量为8 ,占8-9   其大小为2, 填充1字节
                    };              所以sizeof(S3)==10

                #pragma pack(pop)   // 恢复先前的pack设置

        空结构体
            示例:
                struct S5 { };
                sizeof( S5 );       // 结果为1
            试想一个“不占空间”的变量如何被取地址、两个不同的“空结构体”变量又如何得以区分呢于是,于是为其分配一个字节的空间用于占位。


    8. 含位域结构体的sizeof

        使用位域的主要目的是压缩存储,其大致规则为:
            1) 如果相邻位域字段的类型相同, 且其位宽之和 <  类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
            2) 如果相邻位域字段的类型相同, 但其位宽之和 >= 类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
            3) 如果相邻位域字段的类型不同, VC6采取不压缩方式,Dev-C++采取压缩方式;
            4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
            5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。

        示例1:
            struct BF1
            {
                char f1 : 3;        第1个字节仅能容纳下f1和f2,所以f2被压缩到第1个字节中
                char f2 : 4;        f3只能从下一个字节开始
                char f3 : 5;
            };                      sizeof(BF1)==2

        示例2:
            struct BF2
            {
                char  f1 : 3;
                short f2 : 4;
                char  f3 : 5;
            };                      VC6中 sizeof(BF2)==6  Dev-C++中sizeof(BF2)==2


        示例3:
            struct BF3
            {
                char f1 : 3;
                char f2;
                char f3 : 5;
            };                      VC6和Dev-C++中 sizeof(BF2)==3

    9. 联合体的sizeof
        整个联合体的sizeof也就是每个成员sizeof的最大值。其成员也可以是复合类型,被作为整体考虑。
        示例1:
            union U
            {
                int i;
                char c;
                S1 s;
            };              sizeof(U)==sizeof(s)。

原创粉丝点击