4-3 对象大小与sizeof运算符
对象大小
正如你在第4.1节——基础数据类型介绍中所学到的,现代计算机的内存通常以字节为单位组织,每个内存字节都有唯一的地址。到目前为止,将内存视为一堆储物格或信箱来存取信息,并将变量视为访问这些储物格或信箱的名称,这种比喻非常有用。
然而这种比喻存在一个不准确之处——大多数对象实际占用的内存超过1字节。单个对象可能使用1、2、4、8甚至更多连续的内存地址。对象占用的内存大小取决于其数据类型。
由于我们通常通过变量名(而非直接通过内存地址)访问内存,编译器能够隐藏特定对象实际占用的字节数细节。当我们在源代码中访问某个变量x时,编译器会根据变量x的类型确定需要检索多少字节数据,并输出相应的机器语言代码来处理这些细节。
即便如此,了解对象占用内存仍有若干实用价值:
首先,对象占用内存越多,其能承载的信息量就越大。
单比特可存储两种可能值:0 或 1:
| bit 0 |
|---|
| 0 |
| 1 |
2位可表示4种可能的值:
| bit 0 | bit 1 |
|---|---|
| 0 | 0 |
| 0 | 1 |
| 1 | 0 |
| 1 | 1 |
3位可表示8种可能的值:
| bit 0 | bit 1 | bit 2 |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 0 | 1 |
| 0 | 1 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 0 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
| 1 | 1 | 1 |
概括而言,一个具有n位(其中n为整数)的对象可存储2n(即2的n次方,通常写作2n)个唯一值。因此,使用8位字节的对象可存储2⁸(即256)种不同值。而使用2字节的对象则能存储2¹⁶(即65536)种不同值!
由此可见,对象的大小决定了其存储唯一值的上限——使用更多字节的对象能存储更多唯一值。我们将在后续讨论整数时深入探讨这一特性。
其次,计算机的可用内存是有限的。每次定义对象时,都会占用一小部分可用内存,且该占用将持续到对象存在期间。由于现代计算机拥有海量内存,这种影响通常微不足道。但对于需要大量对象或数据的程序(例如渲染数百万多边形的游戏),使用1字节对象与8字节对象之间的差异可能非常显著。
关键洞见
新手程序员常过度专注于优化代码以尽可能减少内存占用。在大多数情况下,这种做法带来的差异微乎其微。应专注于编写可维护的代码,仅在优化能带来实质性收益时才进行优化。
基本数据类型的大小
接下来的问题显然是“给定数据类型的对象占用多少内存?”。令人惊讶的是,C++标准并未明确定义任何基本类型的精确大小(以位为单位)。
相反,标准规定如下:
- 对象必须至少占用1字节(确保每个对象拥有独立的内存地址)。
- 字节必须至少为8位。
- 整数类型char、short、int、long和long long的最小尺寸分别为8位、16位、16位、32位和64位。
- char和char8_t恰好为1字节(至少8位)。
命名法
当我们谈论某种类型的大小时,实际上指的是该类型实例化对象的大小。
在本教程系列中,我们将通过一些适用于现代架构的合理假设来呈现简化视图:
- 字节为8位。
- 内存支持字节寻址(可独立访问内存中的每个字节)。
- 浮点运算支持符合IEEE-754标准。
- 我们采用32位或64位架构。
基于上述假设,我们可以合理地得出以下结论:
| Category | Type | Minimum Size | Typical Size |
|---|---|---|---|
| Boolean | bool |
1 byte | 1 byte |
| Character | char |
1 byte (exactly) | 1 byte |
wchar_t |
1 byte | 2 or 4 bytes | |
char8_t |
1 byte | 1 byte | |
char16_t |
2 bytes | 2 bytes | |
char32_t |
4 bytes | 4 bytes | |
| Integral | short |
2 bytes | 2 bytes |
int |
2 bytes | 4 bytes | |
long |
4 bytes | 4 or 8 bytes | |
long long |
8 bytes | 8 bytes | |
| Floating point | float |
4 bytes | 4 bytes |
double |
8 bytes | 8 bytes | |
long double |
8 bytes | 8, 12, or 16 bytes | |
| Pointer | std::nullptr_t |
4 bytes | 4 or 8 bytes |
提示
为实现最大可移植性,不应假设对象大于指定的最小尺寸。
或者,若需假设某类型具有非最小尺寸(例如 int 至少占用 4 字节),可使用 static_assert 使编译器在架构不符时终止构建。具体实现方法详见第 9.6 课——Assert 与 static_assert。
相关内容
您可以在这里找到更多关于C++标准对各种类型最小尺寸规定的信息。
sizeof 运算符
为确定特定机器上数据类型的大小,C++ 提供了一个名为 sizeof 的运算符。sizeof 运算符sizeof operator是一元运算符,可接受类型或变量作为参数,并返回该类型对象的大小(以字节为单位)。您可以编译并运行以下程序来了解某些数据类型的大小:
#include <iomanip> // for std::setw (which sets the width of the subsequent output)
#include <iostream>
#include <climits> // for CHAR_BIT
int main()
{
std::cout << "A byte is " << CHAR_BIT << " bits\n\n";
std::cout << std::left; // left justify output
std::cout << std::setw(16) << "bool:" << sizeof(bool) << " bytes\n";
std::cout << std::setw(16) << "char:" << sizeof(char) << " bytes\n";
std::cout << std::setw(16) << "short:" << sizeof(short) << " bytes\n";
std::cout << std::setw(16) << "int:" << sizeof(int) << " bytes\n";
std::cout << std::setw(16) << "long:" << sizeof(long) << " bytes\n";
std::cout << std::setw(16) << "long long:" << sizeof(long long) << " bytes\n";
std::cout << std::setw(16) << "float:" << sizeof(float) << " bytes\n";
std::cout << std::setw(16) << "double:" << sizeof(double) << " bytes\n";
std::cout << std::setw(16) << "long double:" << sizeof(long double) << " bytes\n";
return 0;
}
以下是作者机器的输出结果:
bool: 1 bytes
char: 1 bytes
short: 2 bytes
int: 4 bytes
long: 4 bytes
long long: 8 bytes
float: 4 bytes
double: 8 bytes
long double: 8 bytes
您的结果可能因编译器、计算机架构、操作系统、编译设置(32位与64位)等因素而有所不同。
尝试对不完整类型(如void)使用sizeof操作符将导致编译错误。
(我:尝试基本类型和void的类型大小的结果如下:)


对于 gcc 用户
若未禁用编译器扩展功能,gcc 会允许 sizeof(void) 返回 1 值,而非触发诊断错误(指针运算)。我们在第 0.10 课——配置编译器:编译器扩展中展示了如何禁用编译器扩展功能。
似乎通过不了[clang version 21.1.8 (Fedora 21.1.8-4.fc43),gcc version 15.2.1 20260123 (Red Hat 15.2.1-7) (GCC)]
您也可以对变量名使用 sizeof 运算符:
#include <iostream>
int main()
{
int x{};
std::cout << "x is " << sizeof(x) << " bytes\n";
return 0;
}

面向高级读者
sizeof 操作符不包含对象使用的动态分配内存。动态内存分配将在后续课程中讨论。
基本数据类型的性能
在现代机器上,基本数据类型的对象运行速度很快,因此使用或复制这些类型时通常无需担心性能问题。
顺带一提……
你可能会认为占用内存较少的类型比占用内存较多的类型更快。但事实并非总是如此。CPU通常针对特定数据大小(如32位)进行了优化,与该大小匹配的类型可能处理得更快。在这样的机器上,32位整型可能比16位短整型或8位字符型更快。


浙公网安备 33010602011771号