• 【c++】【转】C++ sizeof 使用规则及陷阱分析


    http://www.cnblogs.com/chio/archive/2007/06/11/778934.html

    sizeof不是函数,更像一个特殊的宏,它是在编译阶段求值得。sizeof作用范围内即()里面的内容是被替换成类型

    int a = 0;
    cout << sizeof(1 == 2) << endl;
    cout << sizeof(a = 3) << endl;
    cout << a << endl;

    输出1,4,0

    sizeof有两种用法:

    (1)sizeof(object) 或 sizeof object 

    也就是对对象使用sizeof,也可以写成sizeof object 的形式

    (2)sizeof(typename)
    也就是对类型使用sizeof,注意这种情况下写成sizeof typename是非法的

    int i = 2;
    cout << sizeof i << endl;//正确
    cout << sizeof int << endl;//错误

    基本数据类型的sizeof

    (1)C++内置数据类型

    char,short int(short),int,long int(long),float,double, long double,long long大小分别是:1,2,4,4,4,8, 8, 8

    unsigned不能影响sizeof的取值。

     (2)函数类型

    int f1(){ return 0; }
    double f2(){ return 0; }
    void f3(){ return; }
    void main()
    {
        cout << sizeof(f1()) << endl;//输出4
        cout << sizeof(f2()) << endl;//输出8
        cout << sizeof(f3()) << endl;//编译时出错
        cout << sizeof(f1) << endl;//编译时出错
        system("pause");
    }

    对函数使用sizeof,在编译阶段会被函数返回值的类型取代

     (3)指针问题

    cout << sizeof(string*) << endl; // 4
    cout << sizeof(int*) << endl; // 4
    cout << sizeof(char****) << endl; // 4

    (4)数组问题

    char a[] = "abcdef";
    char b[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
    int c[20] = { 3, 4 };
    char d[2][3] = { "aa", "bb" };
    cout << sizeof(a) << endl; // 7, 表示字符串
    cout << sizeof(b) << endl; // 6, 仅表示字符数组
    cout << sizeof(c) << endl; // 80
    cout << sizeof(d) << endl; // 6
    cout << sizeof(*a) << endl;//1
    cout << sizeof(*b) << endl;//1
    cout << sizeof(*c) << endl;//4
    cout << sizeof(*d) << endl;//3

    注意陷阱:(数组名与指针的区别)

    int *d = new int[10];
    cout<<sizeof(d)<<endl; // 4

    (5)向函数传递数组的问题。

    数组名作为函数参数时会自动退化成同类型的指针

    复杂数据类型中sizeof及其数据对齐问题

     (1)、union的sizeof问题与cpu的边界对齐

     考虑下面问题(默认对齐方式):

    void main()
    {
        union u//8对齐
        {
            double a;
            int b;
        };
        union u2//4对齐
        {
            char a[13];
            int b;
        };
        union u3
        {
            char a[13];
            char b;
        };
    
        cout << sizeof(u) << endl;//8
        cout << sizeof(u2) << endl;//16
        cout << sizeof(u3) << endl;//13
        system("pause");
    }

    union的大小取决于它所有的成员中,占用空间最大的一个成员的大小。所以对于u来说,大小就是最大的double类型成员a了,所以sizeof(u)=sizeof(double)=8。但是对于u2和u3,最大的空间都是char[13]类型的数组,为什么u3的大小是13,而u2是16呢?关键在于u2中的成员int b。由于int类型成员的存在,使u2的对齐方式变成4(4字节对齐),也就是说,u2的大小必须在4的对界上,所以占用的空间变成了16(最接近13的对界)。

     结论:复合数据类型,如union,struct,class的对齐方式为成员中对齐方式最大的成员的对齐方式。
    (2)、struct的sizeof问题

     因为对齐问题使结构体的sizeof变得比较复杂,看下面的例子:(默认对齐方式下)

    void main()
    {
        struct s1
        {
            char a;
            double b;
            int c;
            char d;
        };
        struct s2
        {
            char a;
            char d;
            int c;
            double b;
        };
        cout << sizeof(s1) << endl;//24
        cout << sizeof(s2) << endl;//16
        system("pause");
    }

     这里数据对齐与struct中元素的顺序相关. 上面例子中只是改变了struct中成员的定义顺序

      同样是两个char类型,一个int类型,一个double类型,但是因为对界问题,导致他们的大小不同。

     计算结构体大小可以采用元素摆放法,我举例子说明一下:首先,CPU判断结构体的对界,根据上一节的结论,s1和s2的对界都取最大的元素类型,也就是double类型的对界8。然后开始摆放每个元素。
        对于s1,首先把a放到8的对界,假定是0,此时下一个空闲的地址是1,但是下一个元素d是double类型,要放到8的对界上,离1最接近的地址是8了,所以d被放在了8,此时下一个空闲地址变成了16,下一个元素c的对界是4,16可以满足,所以c放在了16,此时下一个空闲地址变成了20,下一个元素d需要对界1,也正好落在对界上,所以d放在了20,结构体在地址21处结束。由于s1的大小需要是8的倍数,所以21-23的空间被保留,s1的大小变成了24。

    对于s2,首先把a放到8的对界,假定是0,此时下一个空闲地址是1,下一个元素的对界也是1,所以b摆放在1,下一个空闲地址变成了2;下一个元素c的对界是4,所以取离2最近的地址4摆放c,下一个空闲地址变成了8,下一个元素d的对界是8,所以d摆放在8,所有元素摆放完毕,结构体在15处结束,占用总空间为16,正好是8的倍数。

    对于struct,class,union中各个成员在摆放时,地址需要是该成员类型大小的整数倍,同时整个struct大小是最大成员对齐大小的整数倍

    类class 中的sizeof特别探讨

    (1)不带virtual函数时

    class A{};
    class B
    {
    private:
        int value;
        double a;
    };
    void main()
    {
        cout << sizeof(A) << endl;//1,使得A的不同的对象在内存中都有着独特的地址
        cout << sizeof(B) << endl;//16
        system("pause");
    }

     (2)带virtual函数时

    class A
    {
    public:
        virtual void foo(){}
    private:
        int m1;
        double m2;
    };
    class B
    {
    public:
        virtual void foo(){}
    private:
        double m2;
        int m1;
    };
    void main()
    {
        cout << sizeof(A) << endl;//24
        cout << sizeof(B) << endl;//24
        system("pause");
    }

    不懂

  • 相关阅读:
    柔性数组成员 (flexible array member)-C99-ZZ
    如何阅读 Redis 源码?ZZ
    linux下网络编程学习——入门实例ZZ
    leetcode Ch2-Dynamic Programming [2014]
    leetcode Ch1-search 2014
    Skip List & Bloom Filter
    指针的引用-ZZ
    leetcode-sudoku solver
    rest framework之过滤组件
    rest framework之渲染器
  • 原文地址:https://www.cnblogs.com/ljygoodgoodstudydaydayup/p/3897330.html
Copyright © 2020-2023  润新知