对象大小和sizeof运算符
本节阅读量:对象大小
正如您在之前所学的那样,现代机器上的内存通常被组织为字节大小的单位,内存的每个字节都有一个唯一的地址。到目前为止,可以将内存视为一堆文件柜或邮箱,我们可以在其中放置和检索信息,将变量视为访问这些文件柜或信箱的名称。
然而,这种类比在一个方面并不十分正确——大多数对象实际上占用超过1个字节的内存。单个对象可以使用1、2、4、8或甚至更多的连续地址。对象使用的内存量基于其数据类型。
由于我们通常通过变量名(而不是直接通过内存地址)访问内存,编译器向我们隐藏了给定对象使用多少字节。当我们访问某个变量x时,编译器知道要检索多少字节的数据(基于变量x的类型),并可以为我们处理该任务。
即使如此,有几个原因可以帮助您了解对象使用了多少内存。
首先,对象使用的内存越多,它可以容纳的信息就越多。
单个比特可以保存2个可能的值,即0或1:
2比特可以保存4个可能的值:00,01,10,11
3比特可以保存8个可能的值:000,001,010,011,100,101,110,111
概括地说,具有n位(其中n是整数)的对象可以保存2^n(2的n次幂,也通常写入2^n)个唯一值。因此,对于8位字节,字节大小的对象可以保存2^8(256)个不同的值。使用2个字节的对象可以保存2^16(65536)个不同的值!
因此,对象的大小限制了它可以存储的唯一值的数量——使用更多字节的对象可以存储更多的唯一值。当我们讨论整数时,我们将进一步探索这一点。
其次,计算机有有限的空闲内存。每次定义对象时,只要对象存在,就会使用该空闲内存的一小部分。由于现代计算机有大量内存,这种影响通常可以忽略不计。然而,对于需要大量对象或数据的程序(例如,渲染数百万个多边形的游戏),使用1字节和8字节对象之间的差异可能非常显著。
关键点
新程序员通常过于关注优化他们的代码,以使用尽可能少的内存。在大多数情况下,这只有微不足道的差异。专注于编写可维护的代码,并仅在效益显著时进行优化。
基本数据类型大小
显而易见的下一个问题是“不同数据类型的变量占用多少内存?”。
也许令人惊讶的是,C++标准没有定义任何基本类型的确切大小。相反,它只为整型和char类型定义了最小大小(以比特为单位),并将所有类型的实际大小留给具体编译器实现定义!C++标准也不假设一个字节是8比特。
在本教程系列中,我们将通过做出一些合理的假设来简化概念,这些假设通常适用于现代架构:
- 一个字节是8比特。
- 内存是字节可寻址的,因此最小的对象是1个字节。
- 浮点数符合IEEE-754标准。
- 我们采用的是32位或64位体系结构。
基于于此,我们可以声明如下:
类别 | 类型 | 最小大小(字节) | 通常大小(字节) |
---|---|---|---|
布尔 | bool | 1 | 1 |
字符 | char | 1 | 1 |
wchar_t | 1 | 2或4 | |
char8_t | 1 | 1 | |
char16_t | 2 | 2 | |
char32_t | 4 | 4 | |
整数 | short | 2 | 2 |
int | 2 | 4 | |
long | 4 | 4或8 | |
long long | 8 | 8 | |
浮点数 | float | 4 | 4 |
double | 8 | 8 | |
long double | 8 | 8或12或16 | |
指针 | std::nullptr_t | 4 | 4或8 |
提示
为了获得最大的可移植性,您不应该假设变量大于指定的最小大小。
或者,如果希望假设类型具有特定大小(例如,int至少为4个字节),则可以使用static_assert使编译器在该假设不成立的架构上编译失败。我们在后续课程中介绍了如何做到这一点——断言和static_assert。
sizeof运算符
为了确定特定机器上数据类型的大小,C++提供了一个名为sizeof的操作符。sizeof运算符是一元运算符,它接受类型或变量,并返回其大小(以字节为单位)。您可以编译并运行以下程序,以了解某些数据类型的大小:
|
|
以下是作者机器的输出:
|
|
您的结果可能因编译器、计算机架构、操作系统、编译设置(32位与64位)等而异…
尝试对不完整的类型(如void)使用sizeof将导致编译错误。
您还可以对变量名使用sizeof运算符:
|
|
|
|
对于高级读者
sizeof不包括对象使用时动态分配的内存。我们将在以后的课程中讨论动态内存分配。
基本数据类型性能
在现代机器上,基本数据类型的对象速度很快,所以使用或复制这些类型时的性能通常不成为问题。
旁白
您可以假设使用较少内存的类型比使用较多内存的类型更快。但这并不总是正确的。CPU通常被优化为处理特定大小的数据(例如32位),并且与该大小匹配的类型可以更快地处理。在这样的机器上,32位int可能比16位short或8位char更快。
