最近在复习c++,看到了sizeof
部分,对使用它来判断变量的长度有一点蒙,在网上四处找资料,在这里做一个总结
环境
- MacOS 64位
- g++ 4.2.1
- 不加任何预编译指令(比如 #pragma pack)
参考内容
这个我就写在前面了,因为这些文字或答案写的真的很好,我后面做的只是把它们整合在一起
普通的变量
1 2 3 4 5
| char c; short s; int i; double d; std::cout << sizeof(c) << " " << sizeof(s) << " " << sizeof(i) << " " << sizeof(d);
|
输出如下
1 2 4 8
非常正常,要多大空间给多大空间
结构体
关于结构体
关于结构体变量分配有几个准则
- 结构体每个成员相对于起始地址的偏移能够被其自身大小整除,如果不能则在前一个成员后面补充字节
- 结构体总体大小能够被最宽的成员的大小整除,如不能则在后面补充字节,否则需要补充字节直到满足要求
简单的例子
1 2 3 4 5 6
| struct S1 { char c; short s; int i; double d; };
|
分析如下
相对复杂的例子
那么,如果把 int 放到第二个呢?为了增加复杂性,再在最后加一个 char 类型的变量,如下
1 2 3 4 5 6 7
| struct S1 { char c; int i; short s; double d; char cc; };
|
分析如下
类的大小
所有指针的大小为8
1
| std::cout << sizeof(char *) << " " << sizeof(int *) << " " << sizeof(double *);
|
以上输出均为8
类中包含方法以及静态成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Base { public: Base() {};
void func() { }
void func2() { } static int data; };
Base b{}; std::cout << sizeof(b) << std::endl;
|
输出为1;
这些方法都是类的所有实例之间共享的,那个静态成员也和实例化的对象无关;
个人觉得就像是js中把方法挂载到prototype上一样;
空类的大小
- 构造函数,析构函数都可以看成是函数,不占空间,
- 因为一个空类也要实例化,所谓类的实例化就是在内存中分配一块地址,每个实例在内存中都有独一无二的地址。
- 所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。
最后输出为1
1 2 3 4 5 6 7 8 9 10
| class Base { public: Base() {}; ~Base() = default; };
Base b{}; std::cout << sizeof(b) << std::endl;
|
类中含有虚函数
关于虚函数的具体情况就不多数了,就是它一个指针指向一个虚函数表,而一个指针占8字节,所以输出都为8
同时,不管加多少虚函数结果都是一样的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Base { public: Base() {};
virtual ~Base() = default; };
class Base2 { public: Base2() {};
virtual void func() {};
virtual ~Base2() = default; };
Base b{}; Base2 b2{}; std::cout << sizeof(b) << " " << sizeof(b2) << std::endl;
|
类中包含属性
把之前结构体里的数据贴过来,输出的结果是一样的,为32
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class Base { public: Base() {}; private: char c; int i; short s; double d; char cc; };
Base b{}; std::cout << sizeof(b) << std::endl;
|
类的继承
这个也只是和属性有关,子类中包含父类的属性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Base { private: char c; int i; short s; };
class Derive : public Base { public: Derive():Base(){}; private: double d; char cc; };
Base b{}; Derive d{};
std::cout << sizeof(b) << " " << sizeof(d) << std::endl;
|
虚类继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| class Base { public: virtual void func() = 0; };
class Derive : public Base { public: Derive() : Base() {}; void func() {} };
int main() { Derive d{}; std::cout << sizeof(Base) << " " << sizeof(d); }
|
输出为 8 8
,说明子类实现了虚类的方法,依然有一个指针指向那个虚方法列表