C语言中数据溢出与精度丢失的解决方案

 更新时间:2026年10月16日 08:39:41   作者:学逆向的  
还在为C语言整数溢出头疼,本文用short和unsigned int实例,带你彻底搞懂有符号溢出是未定义行为、无符号溢出为何会模2^n回绕,还有movsx与movzx指令的区别,避免优化后代码结果突变,需要的朋友可以参考下

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

#include <stdio.h>
int main() {
    short num = 0x7FFF;
    printf("%hd \r\n", num);
    num = 0x8000;
    printf("%hd \r\n", num);
    return 0;
}
  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. 调试自增演示
short num = 32767;
num++;   // 32767 +1,二进制进位,最高位变成1
printf("%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>
int main() {
    unsigned int num = 4294967295;
    printf("%u \r\n", num);
    num++;
    printf("%u \r\n", num);
    return 0;
}
  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赋值0xFFFFFFFF
mov eax,dword ptr [num]
push eax
push offset string "%u \r\n"
call _printf
add esp,8

mov eax,dword ptr [num]
add eax,1          ; eax = eax + 1
mov 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

以上就是C语言中数据溢出与精度丢失的解决方案的详细内容,更多关于C语言数据溢出与精度丢失的资料请关注脚本之家其它相关文章!

相关文章

  • C/C++实现控制台输出不同颜色字体的方法

    C/C++实现控制台输出不同颜色字体的方法

    这篇文章主要介绍了C/C++实现控制台输出不同颜色字体的方法,涉及C++控制台文字属性相关设置操作技巧,需要的朋友可以参考下
    2017-09-09
  • C语言实现两个矩阵相乘

    C语言实现两个矩阵相乘

    这篇文章主要为大家详细介绍了C语言实现两个矩阵相乘的程序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-05-05
  • opencv C++模板匹配的简单实现

    opencv C++模板匹配的简单实现

    这篇文章主要介绍了opencv C++模板匹配的简单实现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-02-02
  • C++第三方日志库Glog基本语法详解

    C++第三方日志库Glog基本语法详解

    这篇文章主要介绍了C++第三方日志库Glog基本语法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-02-02
  • 一文掌握scanf的用法实例小结

    一文掌握scanf的用法实例小结

    scanf的基本用法除了常规的输入操作外还有一些特殊的用法,使用这些用法可以很方便的在输入中读取想要的数据,这篇文章主要介绍了scanf的用法,需要的朋友可以参考下
    2023-12-12
  • Qt GUI图形图像开发之Qt表格控件QTableView简单使用方法及QTableView与QTableWidget区别

    Qt GUI图形图像开发之Qt表格控件QTableView简单使用方法及QTableView与QTableWidget区

    这篇文章主要介绍了Qt GUI图形图像开发之Qt表格控件QTableView简单使用方法,需要的朋友可以参考下
    2020-03-03
  • 插入排序的顺序表实现代码

    插入排序的顺序表实现代码

    这篇文章主要介绍了插入排序的顺序表实现代码,有需要的朋友可以参考一下
    2014-01-01
  • C/C++之变量对象的创建栈与堆方式

    C/C++之变量对象的创建栈与堆方式

    文章比较了C/C++中栈与堆内存分配的核心区别,指出栈由编译器自动管理、生命周期与作用域绑定,适合小型短期对象;堆需手动分配释放,支持动态需求和跨作用域访问,但易引发内存泄漏,推荐使用智能指针提升安全性
    2025-09-09
  • C++中关于set删除的一些坑

    C++中关于set删除的一些坑

    这篇文章主要介绍了C++中关于set删除的一些坑,因为这个问题浪费了很多的时间,所以想着分享出来给大家,方便同样遇到这个问题的朋友们,有需要的朋友们下面来一起看看吧。
    2017-02-02
  • 解析之C++的列表初始化语法

    解析之C++的列表初始化语法

    有朋友在使用std::array时发现一个奇怪的问题:当元素类型是复合类型时,编译通不过。按说std::array和原生数组的行为几乎是一样的,可为什么当元素类型不同时,初始化语法还会有差别?这篇文章会介绍这个问题的原理,以及正确的解决方式。
    2021-05-05

最新评论