基本数据类型¶
数据类型(Data Type)是⼀种属性,它告诉编译器如何解释存储在计算机内存中的某段数据。数据类型决定了数据的存储⼤⼩、布局、值范围以及可以对该数据执⾏哪些操作。
C++ 提供了多种数据类型,包括基本数据类型、复合数据类型和特殊数据类型,本篇主要讲解的是 C++ 的基本数据类型。
基本数据类型分为整数型、浮点型、字符型、布尔型、空类型。它们在各自对应的应用场景中都有着不可或缺的重要性,接下来对这些数据类型进行逐步的学习。
整数型¶
整数型可以理解为在内存中开辟一个专门用于存储整数的空间,根据要存放的数字大小以及是否需要表示负数,可以采用不同的整数型关键字来开辟所需大小的空间。
在 C++ 中,整数类型(如 int、char、int8_t 等)分为 ** 有符号(signed)和无符号(unsigned)** 两种,核心区别是:是否能表示负数、二进制最高位的用途、数值范围。
|对比项 | 有符号类型 signed | 无符号类型 unsigned | | 能否存负数 | 可以 | 不可以(只能 ≥0)| |最高位含义| 是符号位(0 = 正,1 = 负) |是数值位(参与计算)| |取值范围| 正负对半分 |从 0 开始到更大的正数|
位数相同,无符号类型能表示的正数更大,有符号类型能表示负数。
有符号整数类型¶
类型 |
占用字节 |
存储范围 |
|---|---|---|
|
2 |
|
|
4 |
|
|
4 或 8 |
依赖于系统和编译器 |
|
8 |
|
无符号整数类型¶
通过在有符号整数类型前添加 unsigned 关键字,可以得到对应的无符号整数类型,无符号整数只能表示非负数(零和正数)。
类型 |
占用字节 |
存储范围 |
|---|---|---|
unsigned short |
2 |
0 到 65535 |
unsigned int |
4 |
0 到 4294967295 |
unsigned long |
4 或 8 |
依赖于系统和编译器 |
unsigned long long |
8 |
0 到 18446744073709551615 |
固定宽度整数类型¶
从 C++ 11 开始引入了固定宽度整数类型,确保在不同平台上具有相同的大小。
类型 |
说明 |
存储范围 |
|---|---|---|
int8_t |
8 位有符号整数 |
-128 到 127 |
uint8_t |
8 位无符号整数 |
0 到 255 |
int16_t |
16 位有符号整数 |
-32768 到 32767 |
uint16_t |
16 位无符号整数 |
0 到 65535 |
int32_t |
32 位有符号整数 |
-2147483648 到 2147483647 |
uint32_t |
32 位无符号整数 |
0 到 4294967295 |
int64_t |
64 位有符号整数 |
-9223372036854775808 到 9223372036854775807 |
uint64_t |
64 位无符号整数 |
0 到 18446744073709551615 |
代码演示:
#include <iostream>
#include <cstdint> // 包含固定宽度整数类型
int main() {
short s = 32767;
int i = 2147483647;
long l = 2147483647;
long long ll = 9223372036854775807;
unsigned int ui = 4294967295;
int32_t i32 = 2147483647;
uint64_t ui64 = 18446744073709551615ULL;
std::cout << "短整型: " << s << std::endl;
std::cout << "整型: " << i << std::endl;
std::cout << "长整型: " << l << std::endl;
std::cout << "超长整型: " << ll << std::endl;
std::cout << "无符号整型: " << ui << std::endl;
std::cout << "32位整型: " << i32 << std::endl;
std::cout << "64位无符号整型: " << ui64 << std::endl;
}
注意
如果存储的数值超出了数据类型所能表示的范围,会发生 整数溢出 。有符号整数溢出是未定义行为,可能导致程序崩溃或产生不可预期的结果。无符号整数溢出则是定义良好的,会对最大值+1取模。
代码演示:
#include <iostream>
int main() {
// 有符号整数溢出 - 未定义行为
int i = 2147483648;
std::cout << "溢出后的有符号整数: " << i << std::endl;
// 无符号整数溢出 - 定义良好的行为
unsigned int ui = 4294967296;
std::cout << "溢出后的无符号整数: " << ui << std::endl;
}
浮点型¶
对于需要存储小数的场景,我们需要使用浮点数据类型来存储,例如:3.14。浮点数用于表示实数,可以表示非常大或非常小的数值,但精度有限。
类型 |
占用大小 |
十进制精度位数 |
数值范围(近似) |
|---|---|---|---|
|
4 |
约 6-7 位 |
1e-38 到 1e38 |
|
8 |
约 15-16 位 |
1e-308 到 1e308 |
|
8, 12, 或 16 |
比 |
比 |
代码演示:
#include <iostream>
int main() {
double d1 = 3.14; // 标准小数表示
double d2 = 3.14e10; // 科学计数法(3.14 x 10^10)
double d3 = 3.14e-10; // 科学计数法(3.14 x 10^-10)
float f = 3.14f; // float类型(带f后缀)
long double ld = 3.14L; // long double类型(带L后缀)
std::cout << "标准小数: " << d1 << std::endl;
std::cout << "科学计数法(大): " << d2 << std::endl;
std::cout << "科学计数法(小): " << d3 << std::endl;
}
注意
浮点类型可以表示非常大或非常小的数,但它们只能近似地表示小数,因为它们在内存中的表示是基于二进制分数的。
浮点类型在计算机中的表示有时会导致出现精度问题,因此在需要进行精确计算的场景(如金融计算)中,应该考虑使用专门的库或整数类型(如定点数)而不是浮点类型。
字符型¶
字符型用于存储单个字符,如字母、数字、标点符号等。C++ 提供了多种字符类型以支持不同的字符集。
类型 |
占用字节 |
说明 |
|---|---|---|
|
1 |
用于存储单个字符,通常是ASCII字符。有符号性取决于编译器 |
|
1 |
明确的有符号字符类型,范围通常是 |
|
1 |
明确的无符号字符类型,范围通常是 |
|
2 或 4 |
宽字符类型,用于表示更大的字符集(如Unicode),大小取决于编译器 |
|
2 |
16位字符类型,用于UTF-16编码(C++11起) |
|
4 |
32位字符类型,用于UTF-32编码(C++11起) |
char 数据类型通常只能用来存储一个字符,也就是 '1' / 'A' 这种单个的字符。如果想要存储一句话这种长字符序列,就需要用到 字符数组 或 字符串类(如 std::string)来实现。
代码演示:
#include <iostream>
int main() {
char character = 'A';
signed char sc = -128;
unsigned char uc = 255;
std::cout << "字符: " << character << std::endl;
std::cout << "字符的ASCII值: " << int(character) << std::endl;
std::cout << "有符号字符: " << static_cast<int>(sc) << std::endl;
std::cout << "无符号字符: " << static_cast<int>(uc) << std::endl;
}
布尔型¶
布尔型也可以称之为逻辑型,这个数据类型只能存储 true (真) / false (假) 两个值。布尔型常用于需要进行逻辑判断的场景。
类型 |
占用字节 |
范围 |
|---|---|---|
|
1 |
只能是 |
代码演示:
#include <iostream>
int main() {
bool isTrue = true;
bool isFalse = false;
std::cout << "isTrue: " << isTrue << std::endl;
std::cout << "isFalse: " << isFalse << std::endl;
// 布尔值在算术表达式中会被转换为整数
std::cout << "true + true = " << isTrue + isTrue << std::endl;
}
空类型¶
空类型代表着没有类型,它不能用于声明变量,主要使用场景是表示函数没有返回值或者函数不需要接收参数。
类型 |
说明 |
|---|---|
|
不表示任何实际的数据类型,用于函数返回值或参数列表 |
代码演示:
#include <iostream>
// 函数不返回任何值
void printMessage() {
std::cout << "这个函数不返回任何值" << std::endl;
// 可以有return语句,但不带任何值
return;
}
// 函数不接受任何参数
void demo(void) {
std::cout << "我不接收任何参数,也不返回任何值" << std::endl;
return;
}
int main() {
printMessage();
demo();
}
基本数据类型转换¶
在 C++ 中,不同类型的数据可以相互转换,但需要注意一些规则和潜在问题
隐式类型转换¶
编译器会自动进行某些类型转换
代码演示:
#include <iostream>
int main() {
int i = 42;
double d = i; // int隐式转换为double
std::cout << "d = " << d << std::endl;
double pi = 3.14;
int j = pi; // double隐式转换为int(小数部分被截断)
std::cout << "j = " << j << std::endl;
// 算术转换:不同类型的操作数会转换为相同类型
double result = i + pi; // i被转换为double,然后与pi相加
std::cout << "result = " << result << std::endl;
}
显式类型转换¶
可以使用显式转换来控制类型转换
代码演示:
#include <iostream>
int main() {
double pi = 3.14;
// C风格转换
int i = (int)pi;
std::cout << "i = " << i << std::endl;
// C++风格转换(推荐)
int j = static_cast<int>(pi);
std::cout << "j = " << j << std::endl;
}
注意
类型转换可能导致数据丢失或意外行为,特别是从浮点类型转换为整数类型时,小数部分会被直接截断而不是四舍五入。从大范围类型转换为小范围类型时可能导致溢出。
数据类型选择建议¶
选择合适的数据类型对于程序的性能、内存使用和正确性都很重要
整数类型选择¶
默认情况下使用 int,它通常是处理器最自然的大小
当需要节省内存且数值范围较小时,使用 short
当 int 不够用时,使用 long long
当需要确保跨平台一致性时,使用固定宽度整数类型(如 int32_t)
当只需要表示非负数时,考虑使用无符号类型
浮点类型选择¶
默认情况下使用 double,它提供了良好的精度和性能平衡
当内存非常有限且精度要求不高时,使用 float
当需要更高精度时,使用 long double
字符类型选择¶
默认情况下使用 char 处理 ASCII 字符
当需要处理 Unicode 字符时,使用 char16_t 或 char32_t
当需要将字符作为小整数使用时,明确使用 signed char 或 unsigned char
sizeof 运算符¶
sizeof 是一个用于获取数据类型或变量所占内存大小的运算符,返回的结果是以字节为单位的 size_t 类型(无符号整数类型)。
基本语法:
sizeof(类型)
sizeof(变量)
sizeof 表达式 // 对于表达式可以省略括号
代码演示:
#include <iostream>
int main() {
int a{10};
double b{3.14};
std::cout << "int 类型大小: " << sizeof(int) << " 字节" << std::endl;
std::cout << "变量 a 的大小: " << sizeof(a) << " 字节" << std::endl;
std::cout << "double 类型大小: " << sizeof(double) << " 字节" << std::endl;
std::cout << "变量 b 的大小: " << sizeof(b) << " 字节" << std::endl;
// sizeof 表达式示例
std::cout << "表达式大小: " << sizeof(a + b) << " 字节" << std::endl;
// 注意:sizeof 不会计算表达式的结果
int c = 0;
std::cout << "sizeof(c = 5) = " << sizeof(c = 5) << std::endl;
std::cout << "c = " << c << std::endl; // c 仍然是 0,因为 sizeof 没有执行赋值
}
不同平台(32位 / 64位)或编译器下,类型大小可能不同。
sizeof 的特点:
在编译期计算: sizeof(int) 在编译阶段就已经确定
不会执行表达式: sizeof 只关心类型,不会真正执行表达式
返回类型为 size_t:这是一个无符号整数类型,定义在
头文件中