☰
C 数据溢出与精度丢失
2026/10/15 5:37:58 网站建设 项目流程

有符号 short 溢出(有符号整数溢出属于未定义行为)

#include<stdio.h>intmain(){shortnum=0x7FFF;printf("%hd \r\n",num);num=0x8000;printf("%hd \r\n",num);return0;}
  1. short:2 字节 = 16bit,默认signed有符号
    ○ 范围:-2^15 ~ 2^15-1,即 -32768 ~ 32767
    ○ 0x7FFF:二进制0111 1111 1111 1111 → 32767(最大值)
    ○ 0x8000:二进制1000 0000 0000 0000 → -32768(最小值)
  2. 调试自增演示
shortnum=32767;num++;// 32767 +1,二进制进位,最高位变成1printf("%hd",num);// 输出 -32768

● 汇编:movsx eax, word ptr [num]
● movsx:符号位扩展,把 16 位 short 扩展到 32 位 eax
● 最高位是 1,代表负数;最高位 0 代表正数
⚠️重点:C 标准里有符号整数溢出是 UB(未定义行为),只是在 VC/VS 编译器下会按补码回绕,不同编译器 / 优化等级结果可能不一样

无符号 unsigned int 溢出(标准定义:模 2^n 取余,行为确定)

#include<stdio.h>intmain(){unsignedintnum=4294967295;printf("%u \r\n",num);num++;printf("%u \r\n",num);return0;}
  1. unsigned int:4 字节 = 32bit,无符号
    ○ 范围:0 ~2^32-1,最大值0xFFFFFFFF = 4294967295
    ○ 0xFFFFFFFF + 1 = 0x100000000
    ○ 只有 32 位存储空间,丢弃进位的最高位 1,剩余0x00000000,结果 = 0
    ✅重点:无符号整数溢出是 C 标准明确定义的,自动对2^32取模,一定会回绕
    反汇编核心片段解析
mov dword ptr[num],0FFFFFFFFh;给num赋值0xFFFFFFFFmov eax,dword ptr[num]push eax push offset string"%u \r\n"call _printf add esp,8mov eax,dword ptr[num]add eax,1;eax=eax+1mov dword ptr[num],eax;写回栈,超出32bit的进位直接丢弃

● add eax,1 加法指令本身会产生进位标志 CF,但存储到 32 位变量时,超出的进位不会保存,直接截断

对比总结表

类型字节溢出行为C 标准规定
signed short232767+1 → -32768未定义行为 UB,仅 VC 下补码回绕
unsigned int44294967295+1 → 0确定,模2^32截断

补充易错点

  1. 不要依赖有符号数溢出回绕写代码,开启 O2 优化后结果可能完全改变
  2. 溢出本质:固定 bit 宽度,加法进位超出存储空间,发生截断;有符号还要额外解释最高位为符号位
  3. movsx(符号扩展)vs movzx(零扩展)
    ○ movsx:有符号类型扩展,高位补符号位
    ○ movzx:无符号类型扩展,高位补 0

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询