//在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$
*/