变量与数据类型

建议先阅读:04_第一个程序与输入输出

原理

内存布局

变量是命名内存区域。类型决定了编译器为该变量分配多少字节以及如何解释这些字节:

类型字节 (x86-64)解释方式
bool10 或 1
char1ASCII 码值,-128~127
int4补码整数,-2³¹ ~ 2³¹-1
long long8补码整数,-2⁶³ ~ 2⁶³-1
float4IEEE 754 单精度 (符号1 + 指数8 + 尾数23)
double8IEEE 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 “解释有符号整数溢出为什么是未定义行为,以及如何安全检测溢出”。