🔷 第二章 C++语言基础
📄 一句话概括

整型变量是一个家族:短整型 short(2 字节)、整型 int(4 字节,日常默认就用它)、长整型 long、超长整型 long long(8 字节)。每种都有范围上限,装不下就溢出——而且不会报错,会"回绕"成一个莫名其妙的数(INT_MAX + 1 变成 INT_MIN,正数一秒变负数)。记住三条:用 sizeof 查字节数;用 <climits> 里的 INT_MAX 查范围;算钱、算大数一律上 long long。

一、整型家族一览(32/64 位 Windows 常见情况)

类型 字节 大致范围 什么时候用
short(short int) 2 −32768 ~ 32767 省内存的场合(嵌入式、大数组)
int 4 −21.4 亿 ~ 21.4 亿 默认选择,够用就用它
long(long int) Windows 4 / Linux 64 位 8 视平台而定 ⚠ 跨平台时不要依赖它
long long 8 −922 京 ~ 922 京 装大数:钱、时间戳、ID

每种都有"无符号版":unsigned int、unsigned short…(省略 int 时写作 unsigned)。无符号的特点是没有负数,正数范围翻倍(unsigned int 能到约 42.9 亿)。

这个表要背的只有一列:short 2、int 4、long long 8。long 那一行记住"不可靠"就够了——它在 Windows 下是 4 字节、在 64 位 Linux 下是 8 字节,是真实存在的移植坑。

二、用 sizeof 亲眼看看

cout << sizeof(short)     << endl;   // 2
cout << sizeof(int)       << endl;   // 4
cout << sizeof(long)      << endl;   // Windows 4 / Linux 8
cout << sizeof(long long) << endl;   // 8

sizeof 不是函数,是运算符——它直接问编译期"这个东西占几字节"。写成 sizeof(int) 或 sizeof(a) 都行(sizeof(a) 也可以写 sizeof a)。

三、查范围:<climits> 里的"最大的数"

#include <climits>        // 或者老写法 <limits.h>

cout << INT_MAX  << endl;    // 2147483647
cout << INT_MIN  << endl;    // -2147483648
cout << SHRT_MAX << endl;    // 32767

背不住具体数字没关系,记住这个头文件:不确定某个类型够不够大时,去查 XXX_MAX / XXX_MIN。

四、核心风险:溢出(Overflow)

int big = INT_MAX;      // 21 亿多,这是 int 的极限
big = big + 1;          // 加一以后会怎样?
cout << big << endl;    // 输出 -2147483648  ← 变成了巨大的负数!

这就是溢出:值超出了类型的范围,多出来的部分"从头绕回去"了(像里程表走满一圈回到 0)。

三个必须记住的事实:

  1. 不会报错、不会警告(多数编译器默认不提示)——它安安静静地给你错结果
  2. 结果看起来毫无道理:正数变负数,大数变小
  3. 这是真实事故的常见来源:库存数量、账户余额、游戏金币、页面浏览量一旦溢出,就会同时影响计算和判断(if (金币 > 0) 的判断也会一起失效)

实战规矩:

场景 选择
一般计数(人数、次数) int 够用
金额(以"分"为单位) long long —— 21 亿分=2100 万元,很容易超
时间戳、ID long long
一定不会有负数的计数 可以用 unsigned,但减法要特别小心

unsigned 的陷阱(提前认识一下):

unsigned int u = 0;
u = u - 1;              // 不会变成 -1!
cout << u;              // 输出 4294967295(变成了最大的无符号数)

所以:无符号类型"看起来安全"(不会有负数),但一旦不小心减过头,会跳成一个巨大的正数——比有符号的溢出更隐蔽。新手建议:不确定就别用 unsigned。

五、动手 Demo:把溢出"抓个现行"

新建 intvar.cpp:

#include <iostream>
#include <climits>            // INT_MAX / SHRT_MAX 在这里
using namespace std;

int main() {
    cout << "int 占 " << sizeof(int) << " 字节" << endl;
    cout << "int 最大 = " << INT_MAX << endl;

    int big = INT_MAX;
    cout << "加一之前:" << big << endl;
    big = big + 1;
    cout << "加一之后:" << big << endl;      // ⚠ 观察这一行

    short s = SHRT_MAX;
    cout << "short 最大 = " << s << " 加一后 = " << (short)(s + 1) << endl;

    long long money = 3000000000LL;           // 30 亿分 = 3000 万元
    cout << "long long 装得下:" << money << endl;
    return 0;
}

看到什么算成功:加一之后 输出一个大负数(一般是 -2147483648)。这就是溢出,悄无声息地发生了。

30 秒实验:把 long big 换成 short big,先赋 SHRT_MAX 再 +1,看它从上万直接跳到 −32768。"回绕"就这么直白。

六、常见误区

  1. "超范围会报错"——不会。溢出不报错、不警告,直接给错值。这是它最危险的地方
  2. "手机号用 int 存就行"——绝对不行。手机号 11 位,超过 21 亿。要么 long long,要么按字符串存
  3. "unsigned 比 int 更安全"——恰恰相反:unsigned 减过头会跳到极大的正数,比负数更隐蔽。而且"有符号与无符号混算"还会触发类型提升的坑(第 3 章)
  4. "long 就是 8 字节"——在 Windows 上它常常是 4 字节。要 8 字节的大数,明确写 long long,别指望 long
自测四问(点开对答案) 1. `short` / `int` / `long long` 各占几字节(Windows)?——2 / 4 / 8。 2. `INT_MAX + 1` 会得到什么?——通常是 `INT_MIN`(−2147483648),**溢出回绕**成了大负数,且不报错。 3. 手机号、金额该怎么存?——**别用 `int`**;金额用 `long long`(以"分"为单位),手机号用 `long long` 或字符串。 4. 查一个类型的最大值该找哪儿?——引入 ``,用 `INT_MAX`、`SHRT_MAX` 这些常量。

相关笔记