变量与数据类型
建议先阅读:04_第一个程序与输入输出
原理
内存布局
变量是命名内存区域。类型决定了编译器为该变量分配多少字节以及如何解释这些字节:
| 类型 | 字节 (x86-64) | 解释方式 |
|---|---|---|
bool | 1 | 0 或 1 |
char | 1 | ASCII 码值,-128~127 |
int | 4 | 补码整数,-2³¹ ~ 2³¹-1 |
long long | 8 | 补码整数,-2⁶³ ~ 2⁶³-1 |
float | 4 | IEEE 754 单精度 (符号1 + 指数8 + 尾数23) |
double | 8 | IEEE 754 双精度 (符号1 + 指数11 + 尾数52) |
char 本质是 1 字节整数——CPU 不区分”字符”和”数字”,只是编译器在 cout 时选择输出字符还是数值。
初始化与未定义行为
局部变量不自动初始化——其值为栈上残留的任意数据。读取未初始化变量是未定义行为(UB)。全局/静态变量则自动初始化为零,因为它们存储在 .bss 段,操作系统在加载时清零。
int global_var; // 自动初始化为 0,存储在 .bss
int main() {
int local_var; // 未初始化,栈上的随机值
// int x = local_var; // 未定义行为!
}浮点精度
浮点数用二进制表示,绝大多数十进制小数无法精确表示。0.1 + 0.2 != 0.3 源于 IEEE 754 的固有限制。浮点比较应使用 epsilon 范围判断。
整数溢出
有符号整数溢出是未定义行为——编译器可能删除相关分支。无符号整数溢出是定义良好的(模 2^n 回绕)。
语法
声明与初始化
int a = 10; // 拷贝初始化
int b(20); // 直接初始化
int c{30}; // 列表初始化 (C++11, 推荐, 禁止窄化转换)
int d{}; // 初始化为 0
auto e = 3.14; // 类型推导: double列表初始化
int x{3.14}直接编译错误,而非静默截断。
const 与 constexpr
const int MAX = 100; // 运行时常量,初始化后不可改
constexpr int SIZE = 50; // 编译时常量,必须编译期可求值
constexpr int square(int x) { return x * x; } // 可在编译期执行
int arr[square(5)]; // arr[25]constexpr 隐式包含 const,但约束更强:值必须在编译时确定。
类型转换
double pi = 3.14159;
int n = pi; // 隐式转换,截断为 3
int m = static_cast<int>(pi); // 推荐: 显式标注意图
int a = 5, b = 2;
double result = static_cast<double>(a) / b; // 2.5,而非 2
static_cast在编译时检查合理性;C 风格(int)pi不做检查。
sizeof
sizeof(int); // 返回编译时常量
sizeof(arr); // 整个数组的字节数
sizeof(arr) / sizeof(arr[0]); // 数组元素个数实践
ASCII 码关键值:'A'=65, 'Z'=90, 'a'=97, 'z'=122, '0'=48, '9'=57。大小写转换差 32。
安全运算——将 int 转为 long long 再运算以防溢出:
long long safe = static_cast<long long>(a) * b;力扣:
力扣: 入门练习 (使用 long long 读入)
力扣: 简单数学题
力扣: 类型综合判断题 (考察多种类型选择)
AI 自检提示:询问 AI “解释有符号整数溢出为什么是未定义行为,以及如何安全检测溢出”。