【C++ 基本数据类型】整型、浮点型、字符型、布尔型及大小

1. 什么是数据类型?

数据类型告诉编译器:要存储什么种类的数据 以及需要分配多少内存空间 。C++ 是一种静态类型语言,变量的类型在编译时就必须确定。

C++ 内置的基本数据类型(也叫算术类型)分为两类:

  • 整型:包括整数、字符、布尔值
  • 浮点型:小数

2. 整型(Integer Types)

整型用于存储整数(没有小数部分的数)。

2.1 整型分类与大小

类型 关键字 典型大小(字节) 取值范围(以32位系统为例)
短整型 short (或 short int) 2 -32,768 ~ 32,767
整型 int 4 -2,147,483,648 ~ 2,147,483,647
长整型 long (或 long int) 4(Windows)/ 8(Linux) 见上或更大
长长整型 long long (C++11) 8 -9.22×10¹⁸ ~ 9.22×10¹⁸

注意:int 的大小取决于编译器和平台(通常为4字节)。C++ 标准只规定了最小大小:short ≥ 2字节,int ≥ 2字节,long ≥ 4字节,long long ≥ 8字节。

2.2 有符号与无符号

  • 有符号 (默认):可以表示负数、零、正数。如 int
  • 无符号 :只能表示非负数,范围更大。用 unsigned 前缀。
cpp 复制代码
unsigned int a = 4000000000;   // 正数范围扩大
signed int b = -100;           // signed 可省略
类型 取值范围(4字节)
int -2,147,483,648 ~ 2,147,483,647
unsigned int 0 ~ 4,294,967,295

2.3 代码示例:查看大小和溢出

cpp 复制代码
#include <iostream>
#include <climits>   // 包含整型极限常量
using namespace std;

int main() {
    cout << "int 大小:" << sizeof(int) << " 字节" << endl;
    cout << "short 大小:" << sizeof(short) << " 字节" << endl;
    cout << "long 大小:" << sizeof(long) << " 字节" << endl;
    cout << "long long 大小:" << sizeof(long long) << " 字节" << endl;

    // 查看最大最小值(climits)
    cout << "int 最大值:" << INT_MAX << endl;
    cout << "int 最小值:" << INT_MIN << endl;
    cout << "unsigned int 最大值:" << UINT_MAX << endl;

    // 演示溢出
    unsigned int u = 0;
    u = u - 1;   // 无符号整数下溢,变成最大值
    cout << "0 - 1 = " << u << " (无符号溢出)" << endl;

    int i = 2147483647; // int 最大值
    i = i + 1;          // 溢出,结果是未定义的(通常是负数)
    cout << "2147483647 + 1 = " << i << " (有符号溢出)" << endl;

    return 0;
}

可能的输出(32位环境):

复制代码
int 大小:4 字节
short 大小:2 字节
long 大小:4 字节
long long 大小:8 字节
int 最大值:2147483647
int 最小值:-2147483648
unsigned int 最大值:4294967295
0 - 1 = 4294967295 (无符号溢出)
2147483647 + 1 = -2147483648 (有符号溢出)

⚠️ 有符号整型溢出是未定义行为,程序可能崩溃或产生奇怪结果。无符号溢出则是按模运算(回绕)。

3. 浮点型(Floating-Point Types)

用于存储实数(带小数点的数),遵循 IEEE 754 标准。

类型 关键字 典型大小(字节) 精度(有效十进制位数) 取值范围(约)
单精度 float 4 6~7 位 ±3.4×10³⁸
双精度 double 8 15~16 位 ±1.7×10³⁰⁸
扩展精度 long double 8/12/16 依平台 更高 更大
cpp 复制代码
#include <iostream>
#include <iomanip>
#include <cfloat>   // 浮点极限常量
using namespace std;

int main() {
    float f = 3.1415926535f;   // f 后缀表示 float
    double d = 3.1415926535;
    long double ld = 3.1415926535L;

    cout << "float 大小:" << sizeof(float) << " 字节" << endl;
    cout << "double 大小:" << sizeof(double) << " 字节" << endl;
    cout << "long double 大小:" << sizeof(long double) << " 字节" << endl;

    // 精度演示:float 只能保留约7位有效数字
    cout << fixed << setprecision(10);
    cout << "float 值   : " << f << endl;   // 可能输出 3.1415927410
    cout << "double 值  : " << d << endl;   // 输出 3.1415926535

    // 浮点比较陷阱
    float f1 = 0.1f;
    float f2 = 0.2f;
    float f3 = f1 + f2;
    if (f3 == 0.3f) {
        cout << "相等" << endl;
    } else {
        cout << "不相等,实际值:" << setprecision(20) << f3 << endl;
    }

    return 0;
}

🔍 浮点精度问题 :0.1 在二进制中是无限循环小数,无法精确表示。因此浮点数比较应该使用容差(如 fabs(a-b) < 1e-6)。

4. 字符型(Character Types)

字符类型用于存储单个字符(本质是小整数,存储 ASCII 或 Unicode 码点)。

类型 说明 典型大小 编码
char 单字节字符 1 字节 ASCII(通常)
signed char 有符号字符 1 字节 -128~127
unsigned char 无符号字符 1 字节 0~255
wchar_t 宽字符(用于国际化) 2 或 4 字节 Unicode (UTF-16/32)
char16_t (C++11) UTF-16 字符 2 字节 UTF-16
char32_t (C++11) UTF-32 字符 4 字节 UTF-32
cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    char ch = 'A';               // 字符字面量用单引号
    char ascii_val = 65;         // 等价于 'A'
    cout << ch << " 的 ASCII 码:" << (int)ch << endl;

    // 字符参与算术运算(按整数)
    char next = ch + 1;
    cout << "A 的后一个字符:" << next << endl;   // 'B'

    // 转义字符
    cout << "换行符:\n,制表符:\t,反斜杠:\\,单引号:\'" << endl;

    // 宽字符示例
    wchar_t wch = L'中';         // L 前缀表示宽字符
    wcout << L"宽字符:" << wch << endl;

    return 0;
}

常见转义字符\n(换行)、\t(制表)、\\(反斜杠)、\'(单引号)、\"(双引号)、\0(空字符)。

5. 布尔型(Boolean Type)

bool 类型用于表示逻辑真或假。它的大小通常为 1 字节(C++ 标准未强制,但大多数编译器实现为1字节)。

cpp 复制代码
#include <iostream>
using namespace std;

int main() {
    bool is_ready = true;
    bool is_empty = false;

    cout << "bool 大小:" << sizeof(bool) << " 字节" << endl;
    cout << "true 的整数值:" << (int)true << endl;   // 1
    cout << "false 的整数值:" << (int)false << endl; // 0

    // 任何非零值转换为 true,零转换为 false
    bool b1 = 100;   // true
    bool b2 = 0;     // false
    bool b3 = -5.5;  // true(非零)

    // 逻辑运算
    bool result = (is_ready && !is_empty);  // true
    cout << boolalpha;  // 让 bool 输出 true/false 而不是 1/0
    cout << "result = " << result << endl;

    return 0;
}

6. 内存模型讲解(浅显易懂)

所有变量在内存中占据连续的字节。不同类型占用的字节数不同,且字节内部的二进制表示也不同。

6.1 整型的内存表示(以 int 为例)

假设有一个 int a = 42;(4字节,小端序,32位系统):

复制代码
内存地址(低 → 高):
地址 1000: 00101010   (0x2A)  ← 最低有效字节
地址 1001: 00000000   (0x00)
地址 1002: 00000000   (0x00)
地址 1003: 00000000   (0x00)
  • 42 的二进制是 ...00101010,低字节存储在第 1000 号地址(小端序)。
  • 有符号整数用补码表示负数。

6.2 浮点型的内存表示(float

float 遵循 IEEE 754 单精度格式:1位符号位 + 8位指数 + 23位尾数。

例如 float f = 3.14f; 在内存中(近似):

复制代码
符号(1) 指数(8)         尾数(23)
0      10000000         10010001111010111000011

这解释了为什么浮点数不能精确表示某些十进制小数。

6.3 字符型的内存表示

字符变量存储的是其 ASCII 码值(一个整数)。例如 char ch = 'A'; 在内存中就是一个字节:

复制代码
地址 2000: 01000001   (十进制 65)

6.4 布尔型的内存表示

bool 变量虽然只表示 0 或 1,但仍占用 1 字节(为了可寻址性)。true 通常存储为 1,false 为 0。

6.5 内存布局示意图

复制代码
内存区域(低地址 → 高地址)
┌────────────────────────────────────────────────────────────┐
│  char c = 'A'   │  int i = 42      │  float f = 3.14   │ ... │
│  [65] (1字节)   │ [2A 00 00 00]    │ [C3 F5 48 40]     │     │
└────────────────────────────────────────────────────────────┘

注意:编译器可能会在变量之间插入填充字节(对齐),以提高访问速度。因此结构体的大小不一定等于成员大小之和。

7. 常见错误与避坑

错误示例 问题 正确做法
float f = 3.14; 字面量 3.14 是 double 类型,会隐式转换 3.14f 后缀
int a = 3.14; 截断小数部分,可能丢失信息 double 或显式转换
char c = "A"; 双引号是字符串,不能用单引号 'A'
bool b = (0.0 == 0); 浮点与整数比较,但 0.0 精确 一般浮点用容差比较
unsigned int u = -1; 无符号变量赋负数,变成大正数 除非有意利用回绕,否则避免

8. 练习题

题目:编写一个 C++ 程序,完成以下任务:

  1. 使用 sizeof 运算符输出当前平台上 char, short, int, long, long long, float, double, long double, bool 所占的字节数。
  2. 定义一个 unsigned short 变量 u16 并赋值为 65535(该类型的最大值),然后对其加 1,输出结果,解释发生了什么。
  3. 定义两个 float 变量 a = 1.0 / 3.0b = 1.0 / 3.0,计算 a * 3.0b * 3.0,分别输出结果,观察它们是否精确等于 1.0。
  4. 定义一个 char 变量并赋值为 'Z',输出它的 ASCII 码(整数值)以及它的下一个字符('Z' + 1)。

期望输出格式示例

复制代码
char: 1 字节
short: 2 字节
...
65535 + 1 = 0 (无符号溢出回绕)
1.0/3.0 * 3.0 = 1 (但实际浮点值可能为 0.999999...)
'Z' 的 ASCII 码: 90, 下一个字符: '['

上期小练习答案

cpp 复制代码
#include <iostream>
using namespace std;

constexpr int kStudentCount = 5;   // 编译时常量
const double kPi = 3.14159;        // 运行时只读常量

int Increment() {
    static int counter = 0;   // 静态局部变量,只初始化一次,生命周期贯穿整个程序
    return ++counter;
}

int main() {
    // 3. 未初始化的局部变量
    int uninit_val;
    cout << "未初始化的值:" << uninit_val << endl;  // 输出垃圾值

    // 4. 测试静态计数器
    cout << "第1次调用:" << Increment() << endl;
    cout << "第2次调用:" << Increment() << endl;
    cout << "第3次调用:" << Increment() << endl;

    // 5. 尝试修改常量(取消注释会编译错误)
    // kPi = 3.14;   // error: assignment of read-only variable 'kPi'

    // 附加挑战
    const int size_const = 10;        // 运行时初始化,但值已知,在支持 VLA 的编译器可能允许
    constexpr int size_constexpr = 10;
    int arr1[size_constexpr];          // 标准 C++ 合法
    int arr2[size_const];              // 标准 C++ 不合法(gcc 扩展允许)
    
    cout << "kStudentCount = " << kStudentCount << endl;
    cout << "kPi = " << kPi << endl;

    return 0;
}

总结:C++ 的基本数据类型包括整型、浮点型、字符型和布尔型,每种类型有固定或平台相关的大小和取值范围。理解它们在内存中的表示(二进制、字节序、IEEE 754)有助于写出高效且无 bug 的代码。下一篇文章我们将学习类型别名与类型推导,让代码更简洁安全。

相关推荐
jerryinwuhan1 天前
RDD第二次练习
开发语言·c#
wechat_Neal1 天前
Golang的车载应用场景
开发语言·后端·golang
weixin_513449961 天前
walk_these_ways项目学习记录第八篇(通过行为多样性 (MoB) 实现地形泛化)--策略网络
开发语言·人工智能·python·学习
飞Link1 天前
逆向兼容的桥梁:3to2 自动化降级工具实现全解析
运维·开发语言·python·自动化
曾阿伦1 天前
Python3 文件 (夹) 操作备忘录
开发语言·python
dong__csdn1 天前
jdk添加信任证书
java·开发语言
君义_noip1 天前
信息学奥赛一本通 4150:【GESP2509七级】⾦币收集 | 洛谷 P14078 [GESP202509 七级] 金币收集
c++·算法·gesp·信息学奥赛·csp-s
Ricky_Theseus1 天前
静态链接与动态链接
c++
南 阳1 天前
Python从入门到精通day64
开发语言·python
花千树-0101 天前
Java 接入多家大模型 API 实战对比
java·开发语言·人工智能·ai·langchain·ai编程