sizeof系列——struct class union

    xiaoxiao2021-03-25  81

    struct:

    struct MyStruct

    {   

       double a;

       char   b;

       int    c;

    };

    sizeof(MyStruct)=?????

    很多朋友会认为结果是:8(sizeof(a))+1(sizeof(b))+4(sizeof(c))=13

    但是当我们在vs上运行输出的结果是 16,这是为什么呢?

    这是编译器为了提高cup的存储速度对一些起始地址进行了"对齐"处理.

    虽然对齐原则和编译器有关联但是以下的原则是必须遵守的:

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

    结构体每个成员相对于结构体首地址偏移量都是成员大小的整数倍,不够就进行字节填充。

    结构体的总大小为最宽数据成员的整数倍,不够就字节填充。

    所以再将目光转向MyStruct:

    第一个变量a首地址偏移量为0,是sizeof(a)=8的整数倍,所以占用8+0=8个字节。

    第二个变量b首地址偏移量为8,是sizeof(b)=1的整数倍,所以占用1个字节,将b放在偏移量为8的地方。

    第三个变量c首地址偏移量8+1=9,不是sizeof(c)=4的整数倍所以进行字节填充9+3=12(离9最近的4的倍数),变量c占用4个字节。

    综上:8+1+3+4=16 16是最大数据类型double=8的整数倍(不用补充字节),所以最后结果是16.

    如果我们将MyStruct的数据位置换一下

    struct MyStruct

    {   

       char a;

       double   b;

       int    c;

    };

    那么sizeof(MyStruct )的结果会是

    sizeof(a)=1;

    sizeof(b)=8;

    sizeof(c)=4;

    (1+7+8+4)=20;(包含了填充字节);

    但是20不是8的整数倍所以填充字节20+4=24(离20最近的8的整数倍)

    当然我们也可以用#pragam pack(n)来终结这种丧心病狂的对齐方式

    eg:

    #pragam pack(push)//保存对齐状态

    #pragam pack(4)(以4字节方式对齐)

    struct Test

       char a;

       double b;

       int   c;

    };

    #pragam pack(pop)

    原则:

    若n>变量字节 采用默认对齐方式

    若n<变量字节 采用n的倍数对齐方式

    若n>所有变量(单个)的字节数,那么总大小为最大变量的整数倍,否则为n的整数倍

    sizeof(Test)=1+3+8+4=13 补齐3个字节=16;

    若把#pragam pack(4)改为#pragam pack(16)

    sizeof(Test)=1+7+8+4+4=24;

    union:

    union Test

    {

       int a;

       double b;

       char c;

    };

    sizeof(Test)

    sizeof(a)=4;

    sizeof(b)=8;

    sizeof(c)=1;

    sizeof(Test)以最长为所有字节 8 又因为8是8的倍数所以最后为8(union以单个最长字节对齐

    class:

    一、个空类

    class A

    };

        求sizeof的结果是1,因为即使是没有成员之类的,一个类存在,至少都要给他一个空间,不然就没有存在的意义了。

    二、简单的类

    class A

    {

        int a;

        virtual fun();

    }

        这个也好求,就是sizeof(A.a)+4(指向虚表的指针)

    三、子类普通继承、父类中不含虚函数

    class  A

    {

        int a;

    }

    class B:public A

    {

         int b;

         virtual fun();

    }

    sizeof(B)=sizeof(A)+sizeof(B.b)+4(指向虚表指针)

    四、子类普通继承、父类含虚函数

    class  A

    {

        int a;

        virtual fun1();

    }

    class B:public A

    {

         int b;

         virtual fun();

    }

    sizeof(B)=sizeof(A)-4(sizeof(A)中有一个指向虚表的指针)+sizeof(B.b)+4(指向虚表指针)

    因为普通继承,子类和父类的虚函数存放在同一个虚表中,所以,只需要存一个指向续表的指针即可;

    五、子类虚继承、父类不含虚函数

    class  A

    {

        int a;

       

    }

    class B:virtual public A

    {

         int b;

         virtual fun();

    }

    sizeof(B)=sizeof(A)+4(指示父类存放空间的起始偏移量)+sizeof(B.b)+4(指向B的虚表的指针)

    六、子类虚继承、父类含虚函数

    class  A

    {

        int a;

        virtual fun1();

       

    }

    class B:virtual public A

    {

         int b;

         virtual fun();

    }

    sizeof(B)=sizeof(A)+4(指示父类存放空间的起始偏移量)+sizeof(B.b)+4(指向B的虚表的指针)

    虚继承时,父类和子类的虚函数表分开放,所以,分别存储两个指向对应续表的指针,因而不用减去sizeof(A)中续表指针的大小。

    转载请注明原文地址: https://ju.6miu.com/read-21805.html

    最新回复(0)