union struct 类 大小

//在C++中编译器会为空对象分配1个字节的空间,就是为了区分空对象占内存的位置。
//分配了一个字节之后,空对象在内存空间上有独一无二的地址

#include <iostream>

using namespace std;

class A         //空类
{

};

struct B        //空结构体
{

};
union C         //空联合体
{

};
int main(int Rgc, const char *argv[])
{
    std::cout << "sizeof(A) = " << sizeof(A) << std::endl;
    std::cout << "sizeof(B) = " << sizeof(B) << std::endl;
    std::cout << "sizeof(C) = " << sizeof(C) << std::endl;
    return 0;
}
/*
gec@ubuntu:/mnt/hgfs/love_you/02$ g++ first.cpp 
gec@ubuntu:/mnt/hgfs/love_you/02$ ./a.out 
sizeof(A) = 1
sizeof(B) = 1
sizeof(C) = 1
gec@ubuntu:/mnt/hgfs/love_you/02$ 

*/

联合体的大小取决于他所有成员中占用空间最大的一个成员的大小。并且对于复合数据类型,如union,struct, class 的对齐方式为成员中最大成员的对齐方式。

 #include <stdio.h>
 
 union U1 {
     int a;        //U1的大小是其中最大的int类型成员a,所以sizeof(U1) = sizeof(int) = 4;
     char b;
 };
 
 union U2 {
     char a[9]; //U2的大小是char[9] 类型的数组,但由于另一个成员double b ,所以要以8对齐,
                //9以8对齐就是补7位到16;
     double b;
 };
 
 union U3 {
     U1 a;        //U3的大小是char[18] 类型的数组,但由于另一个成员U2 b; ,所以要以8对齐,
                  //18以8对齐就是补6位到24;
     U2 b;
     char c[18];
 };
 int main() {
     printf("size of U1: %ld\n", sizeof(U1));
     printf("size of U2: %ld\n", sizeof(U2));
     printf("size of U3: %ld\n", sizeof(U3));
     return 0;
 }
/*
gec@ubuntu:/mnt/hgfs/love_you/02$ g++ demo1.cpp 
gec@ubuntu:/mnt/hgfs/love_you/02$ ./a.out 
size of U1: 4
size of U2: 16
size of U3: 24
gec@ubuntu:/mnt/hgfs/love_you/02$ 

*/

偏移量

          struct stru 
         {  
                    int a;     //偏移量 0
                    char b;  //偏移量 4
                    int c;     //偏移量 8
         };

      偏移量指的是结构体变量中成员的地址和结构体变量地址的差。结构体大小等于最后一个成员的偏移量加上最后一个成员的大小。显然,结构体变量中第一个成员的地址就是结构体变量的首地址。比如上面的结构体,第一个成员a的偏移量为0。第二个成员b的偏移量是第一个成员的偏移量加上第一个成员的大小(0+4),其值为4;第三个成员c的偏移量是第二个成员的偏移量应该是加上第二个成员的大小(4+1)。


三、在实际中,存储变量时地址要求对齐,编译器在编译程序时会遵循两条原则:

     (1)结构体变量中成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍) 

     (2)结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数

 #include <stdio.h>
 
 struct U1 {
     int a;    //偏移量 0
     char b;   //偏移量 4 上一个占4 字节对齐 占4
 };            //4+4=8
 
 struct U2 {
     char a[9];    //偏移量0   占9  //下一个占8 字节对齐 补7字节
     double b;     //偏移量16
 };                //16+8=24
 
 struct U3 {
     U1 a;           //偏移量 0 占8
     U2 b;           //偏移量 8 占24  上一个占4 char[9]分为 4 4 最后一字节下一个占8 补7字节
     char c[18];     //偏移量 32 占18 上一个占8 补6字节
 };                  //8+24+24=56
  struct U4 {
    char d;        //偏移量 0 占1
     char c[18];    //偏移量 1 占18
 };                //1+18=19
 int main() {
     printf("size of U1: %ld\n", sizeof(U1));
     printf("size of U2: %ld\n", sizeof(U2));
     printf("size of U3: %ld\n", sizeof(U3));
          printf("size of U4: %ld\n", sizeof(U4));
     return 0;
 }
/*
gec@ubuntu:/mnt/hgfs/love_you/02$ g++ demo1.cpp 
gec@ubuntu:/mnt/hgfs/love_you/02$ ./a.out 
size of U1: 8
size of U2: 24
size of U3: 56
size of U4: 19
gec@ubuntu:/mnt/hgfs/love_you/02$ 
跟前一个和后一个进行对比  取较大值对齐

*/

 类大小

#include <iostream>

class CBase         // 空类  //占一字节
{                   //在C++中编译器会为空对象分配1个字节的空间,
                    //就是为了区分空对象占内存的位置。
};                  //分配了一个字节之后,空对象在内存空间上有独一无二的地址。

class CBase1        //非空类    //与结构体对齐方式一致 占16字节
{
    int  a;         //非静态成员变量       属于对象上
    char *p;        //非静态成员变量       属于对象上
};

class CBase2        //带虚函数类   
{
public:
    CBase2(void);
    virtual ~CBase2(void);  //偏移 0
private:
    int   a;                //偏移 8
    char *p;                //偏移 16   占24字节
};
/*
    有虚函数的时候有一个指向虚函数的指针(vptr),
    在64位系统分配指针大小为8字节
*/

class CChild : public CBase2    //继承虚函数类
{              //子类的大小是本身成员变量的大小加上父类的大小。
public:
    CChild(void);
    ~CChild(void);
private:                //父类 偏移 0
    int b;              //偏移24 上一个占8字节 补齐 
};                      //占32字节

class CBase3        //虚函数
{
    virtual void FuncA();
    virtual void FuncB(); 
};  //占8字节
/*
    有虚函数的时候有一个指向虚函数的指针(vptr),
    在64位系统分配指针大小为8字节
*/

class CBase4             //静态成员
{
  int a;                //偏移0 下一个占 8 补齐
  static int b;         //静态成员变量   不属于对象上
  virtual void FuncA(); //偏移8 
};                      //占16
/*
    静态数据成员被编译器放在程序的一个global data members中,
    它是类的一个数据成员.但是它不影响类的大小,
    不管这个类实际产生了多少实例,还是派生了多少新的类,
    静态成员数据在类中永远只有一个实体存在。
    而类的非静态数据成员只有被实例化的时候,
    他们才存在.但是类的静态数据成员一旦被声明,
    无论类是否被实例化,它都已存在.可以这么说,
    类的静态数据成员是一种特殊的全局变量
*/
class CBase5         //普通成员函数
{
    void FuncA();
};
/*
    类的大小与它的构造函数、
    析构函数和其他成员函数无关,
    只已它的数据成员有关。
*/
class A         //普通继承
{
    int a;
};
class B
{
  int b;
};
class C : public A, public B //父类 A占4字节 父类 B占4字节
{
  int c;//偏移8 
};      //占 12字节
//普通的继承,就是基类的大小,加上派生类自身成员的大小

class D : virtual public A, virtual public B   //虚拟继承
{           //父类 A占4字节 父类 B占4字节
            //虚表指针 偏移8 
  int c;    //偏移16 补齐
};          //占24字节

int main(int argc, const char *argv[])
{
    std::cout << "sizeof(CBase) = " << sizeof(CBase) << std::endl;
    std::cout << "sizeof(CBase1) = " << sizeof(CBase1) << std::endl;
    std::cout << "sizeof(CBase2) = " << sizeof(CBase2) << std::endl;
    std::cout << "sizeof(CBase3) = " << sizeof(CBase3) << std::endl;
    std::cout << "sizeof(CBase4) = " << sizeof(CBase4) << std::endl;
    std::cout << "sizeof(CBase5) = " << sizeof(CBase5) << std::endl;
    std::cout << "sizeof(C) = " << sizeof(C) << std::endl;
    std::cout << "sizeof(D) = " << sizeof(D) << std::endl;
    std::cout << "sizeof(CChild) = " << sizeof(CChild) << std::endl;
    return 0;
}
/*
gec@ubuntu:/mnt/hgfs/love_you/02$ g++ demo1.cpp 
gec@ubuntu:/mnt/hgfs/love_you/02$ ./a.out 
sizeof(CBase) = 1
sizeof(CBase1) = 16
sizeof(CBase2) = 24
sizeof(CBase3) = 8
sizeof(CBase4) = 16
sizeof(CBase5) = 1
sizeof(C) = 12
sizeof(D) = 24
sizeof(CChild) = 32
gec@ubuntu:/mnt/hgfs/love_you/02$ 

*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

物の哀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值