Skip to content

C++ 数据类型

变量是内存中命名的存储位置,用于保存程序可以操作的数据。在 C++ 中声明变量时,你需要指定它的数据类型。数据类型会告诉编译器:

  • 为变量分配多少内存。
  • 该内存中可以存储的值的范围或种类。
  • 可以对该变量执行的操作集合。

C++ 提供了一组基本数据类型,通常称为原始类型。以下是一些最常见的类型:

注意:对于现代 Unicode 支持,C++11 引入了 char16_t(用于 UTF-16)和 char32_t(用于 UTF-32),C++20 添加了 char8_t(用于 UTF-8)。然而,std::string 通常使用 char 来处理 UTF-8 编码的文本。

大多数整型和字符型可以使用这些关键字进行修饰:

  • signed:显式表明该类型可以存储正负值(通常是 int 等类型的默认设置)。
  • unsigned:将类型限制为只能存储非负值(0 和正值),相对于其 signed 对应类型,这有效地使最大正值翻倍。
  • short:暗示该整型应比 int 使用更少的内存(至少 16 位)。
  • long:暗示该整型应至少使用与 int 一样多的内存(至少 32 位)。
  • long long:(C++11)保证至少为 64 位的整型。

这些类型的精确大小(以字节为单位)和值范围是实现定义的,这意味着它们可能因编译器、操作系统和硬件架构而异。但是,标准保证了最小范围。下表显示了常见 32 位和 64 位系统上的典型值。请勿依赖这些精确大小编写可移植的代码。 请使用 <limits> 头文件获取精确信息。

你可以使用 sizeof() 运算符来确定特定系统上某个类型或变量的精确大小:

#include <iostream>
#include <string> // 包含 std::string
int main() {
std::cout << "Size of bool: " << sizeof(bool) << " bytes" << std::endl;
std::cout << "Size of char: " << sizeof(char) << " bytes" << std::endl;
std::cout << "Size of int: " << sizeof(int) << " bytes" << std::endl;
std::cout << "Size of short int: " << sizeof(short int) << " bytes" << std::endl;
std::cout << "Size of long int: " << sizeof(long int) << " bytes" << std::endl;
std::cout << "Size of long long int: " << sizeof(long long int) << " bytes" << std::endl;
std::cout << "Size of float: " << sizeof(float) << " bytes" << std::endl;
std::cout << "Size of double: " << sizeof(double) << " bytes" << std::endl;
std::cout << "Size of long double: " << sizeof(long double) << " bytes" << std::endl;
std::cout << "Size of wchar_t: " << sizeof(wchar_t) << " bytes" << std::endl;
std::cout << "Size of std::string: " << sizeof(std::string) << " bytes" << std::endl; // 注意:这是对象的大小,而非存储文本的大小!
return 0;
}

输出会因你的系统而异。请注意,sizeof(std::string) 给出的是字符串对象本身的大小(该对象管理文本),而不是它可能包含的文本长度。

你可以使用 using 关键字(现代 C++ 中更推荐)或较旧的 typedef 关键字为现有类型创建一个新名称(别名)。这可以提高复杂类型的可读性。

语法 (using):

using NewTypeName = ExistingType;

示例:

using Distance = double; // 'Distance' is now an alias for 'double'
using Counter = unsigned long long; // 'Counter' is an alias for 'unsigned long long'
Distance earthToMoon = 384400.0; // Units might be kilometers
Counter worldPopulation = 8000000000;

语法 (typedef - 旧式):

typedef ExistingType NewTypeName;

示例 (typedef):

typedef int ErrorCode;
ErrorCode fileNotFound = 404;

枚举允许你定义一种新类型,该类型具有一组受限的命名整数常量(枚举成员)。它们通过使用有意义的名称代替任意数字来提高代码清晰度。

1. 非限定作用域枚举 (enum) (传统 C 风格)

enum Color {
RED, // 默认值为 0
GREEN, // 默认值为 1
BLUE // 默认值为 2
};
Color myColor = GREEN; // 变量 'myColor' 持有与 GREEN 关联的值 (1)
// 枚举成员会污染周围的作用域:
// int RED = 5; // 错误!RED 已经被定义了。
// 隐式转换为 int:
int colorValue = myColor; // OK: colorValue 变为 1

你可以指定特定的整数值:

enum Status {
PENDING = 10,
PROCESSING = 20,
COMPLETE = 30,
FAILED // 默认值为 31 (前一个值 + 1)
};

2. 限定作用域枚举 (enum class) (现代 C++ - 推荐)

C++11 中引入的 enum class(或 enum struct)提供了更强的类型安全性,并避免了污染周围作用域。

enum class SignalColor {
RED, // 值为 0
YELLOW, // 值为 1
GREEN // 值为 2
};
// 必须使用作用域解析运算符 (::)
SignalColor trafficLight = SignalColor::GREEN;
// 名称具有作用域,不会冲突:
int RED = 100; // OK,这与 SignalColor::RED 不同
// 不能隐式转换为 int:
// int lightValue = trafficLight; // 错误!
// 如果需要,必须显式转换:
int lightValue = static_cast<int>(trafficLight); // OK: lightValue 变为 2
if (trafficLight == SignalColor::GREEN) {
std::cout << "Go!" << std::endl;
}

在现代 C++ 中通常首选 enum class,因为它不会将其枚举成员泄露到周围的作用域,并且防止了意外的隐式转换为整型,从而产生更安全、更易于维护的代码。