【C++】常见易犯错误之数值类型取值溢出与截断(1)
1. 数据类型数值范围溢出
如标题所述,该错误出现的原因是由于变量的值超出该数据类型取值范围而导致的错误。
例题如下:
(IDE环境:C-Free,编译器为mingw5,如下图)

# include <iostream>
int main(){
short int a = ; // short int 取值范围:-32768~32768
short b = ; // short 是short int 的缩写
int c = a + b; // int 取值范围:-2147483648 ~2147483648
short d = a + b;
std::cout << c << ' ' << d << std::endl;
return ;
}
运行结果:

分析原因:a在内存中存储如下,其中第一位是符号位,0表示为正数,1表示负数。
| 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
那么 a + b 在内存如下:
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
对于 “int c = a + b;” 由于c的取值范围为 -2147483648 ~2147483648,共32位,其中31位数据位,1位符号位,a + b 在c的取值范围内,其符号位依然是0,所以c的取值正常,为32768。
| 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
反观“short d = a + b;”其取值范围是 -32768~32768,共16位,其中15位数据位,1位符号位,d在内存中内容如下,其符号位为1,表示为负数,又因为数据在内存是以补码存储的,正数的原码反码补码相同,复数的补码是其反码加1,复数的补码的补码就是复数的原码。所以该内存存储形式的反码为 1111 1111 1111 1111,原码 1000 0000 0000 0000,换成10进制-32768(而不是-0).
| 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
为了验证上述说明的正确性,在VS2015中重新运行,并打印结果的十六进制形式。
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <iostream>
#include <cstddef> int main() {
short int a = ;
short b = ;
int c = a + b;
short d = a + b;
printf("%d: Dec: %d; Hex: %x; size: %d;\n",c, c, c, sizeof(c));
printf("%d: Dec: %d; Hex: %x; size: %d\n",d, d, d, sizeof(d));
printf("%d: Dec: %d; Hex: %x; size: %d\n", d+, d + , d + , sizeof(d + )); system("pause");
return ;
}
结果如下:

对于c的结果,上述分析是正确的;而对于分析d的结果,似乎存在偏差。上述分析中对于d只有16位,而真正表示成十六进制时,却用到了32位,多分配了一倍的位数用来表示(但因为是short型,实际仍然只占2个字节),形成了向最高位借1(最低位是第0位).而为什么会形成这种问题,而不是上述分析那样,暂时不明白(手动标红,待解决)。(已解决,详情查看“【C++】常见易犯错误之数值类型取值溢出与截断(2)”)为了验证编译器为解决这种取值范围溢出,自动多分配1倍内存来表示,做下面实验。
// ConsoleApplication1.cpp : 定义控制台应用程序的入口点。
// #include "stdafx.h"
#include <iostream>
#include <iostream>
#include <cstddef> int main() {
system("color 3f");
short int a = ;
short b = ;
int c = a + b;
short d = a + b;
printf("%d: Dec: %d; Hex: %x; size: %d;\n",c, c, c, sizeof(c));
printf("%d: Dec: %d; Hex: %x; size: %d\n",d, d, d, sizeof(d));
printf("%d: Dec: %d; Hex: %x; size: %d\n", d+, d + , d + , sizeof(d + )); std::cout << "\n" << std::endl;
char f = ;
char g = ;
char h = f + g;
printf("%d: Dec: %d; Hex: %x; size: %d\n\n", h, h, h, sizeof(h));
system("pause");
return ;
}
结果:

char型取值范围-128~127,编译器为了解决这个问题,并非多分配一倍,在这里多分配了三倍内存表示,即内存中同样共用了32位来表示,但实际只占有1个字节。这是为什么呢,待解决,标红!
注:网上有这样一种负数的补码计算方式:模 - 该数的绝对值【1】
例:-1补码:1 0000 0000 - 0000 0001 = 1111 1111;
-3补码:1 0000 0000 - 0000 0011 = 1111 1101;
2. 数据类型数值范围截断
发生截断的例子参考这里第(6)
参考文献
【1】-128在内存中如何存储
https://blog.csdn.net/magiclyj/article/details/75258195
【C++】常见易犯错误之数值类型取值溢出与截断(1)的更多相关文章
- 【C++】常见易犯错误之数值类型取值溢出与截断(3)
0. 前言 本节是“[C++]常见易犯错误之数值类型取值溢出与截断(1)” 的补充,主要探讨浮点型的取值溢出. 1. 相关知识 (1) 浮点型数据取值范围如下: 单精度型 float 3.4 * 1 ...
- 【C++】常见易犯错误之数值类型取值溢出与截断(2)
本节内容紧接上节,解决红色字体遗留问题.本节所有例子运行环境: win10 + VS2015 + X64 + debug 在上节例子中,查看变量 c .d .d+1 的类型. //// Console ...
- 编程中易犯错误汇总:一个综合案例.md
# 11编程中易犯错误汇总:一个综合案例 在上一篇文章中,我们学习了如何区分好的代码与坏的代码,如何写好代码.所谓光说不练假把式,在这篇文章中,我们就做一件事——一起来写代码.首先,我会先列出问题,然 ...
- [golang 易犯错误] golang 局部变量初始化:=的陷阱
我们知道,golang中局部变量初始化方法(使用“:=”创建并赋值),让我们在使用变量时很方便.但是,这也是易犯错误的地方之一.特别是这个初始化符还支持多个变量同时初始化,更特别的是它还支持原有变量赋 ...
- java代码书写易犯错误
java代码书写易犯错误: 常见报错: 控制台报错: 找不到或无法加载主类 HelloWorld 原因: java.lang.NoClassDefFoundError: cn/itcast/day01 ...
- 带符号的char类型取值范围为什么是-128——127
以前经常看到带符号的char类型取值范围是-128——127,今天突然想为什么不是-127——127,-128是怎么来的? 127好理解,char类型是8位,最高位是符号位,0正1负,所以011111 ...
- byte类型取值范围以及溢出具体解释
例1: public class test { public static void main(String[] args) { byte a = 127 ; a = (byte)(a+3) ; Sy ...
- signed char类型取值范围计算
在C语言程序中,给定一个类型,如何计算这个类型变量的取值范围呢?比如有一个字符型变量定义如下: signed char c: 这个字符变量c的取值范围是[-128,127],是计算出来的呢? 假设字符 ...
- Java开发者易犯错误Top10
本文总结了Java开发者经常会犯的前十种错误列表. Top1. 数组转换为数组列表 将数组转换为数组列表,开发者经常会这样做: List<String> list = Arrays.asL ...
随机推荐
- P4168 蒲公英
神仙分块,把减写成加调了半小时.. 不过这题也启示我们其实有的分块题要把多个块的信息拿到一起维护 以前做的都是每个块的信息单独维护 写的分块题还不太多,同时维护一个块的左右边界好像有点冗余,不过这样代 ...
- 聊聊select, poll 和 epoll_wait
聊聊select, poll 和 epoll 假设项目上需要实现一个TCP的客户端和服务器从而进行跨机器的数据收发,我们很可能翻阅一些资料,然后写出如下的代码. 服务端 客户端 那么问题来了,如果有一 ...
- Mysql 远程连接错误排查
1. 测试本地与远程服务器端口能否连通 telnet 远程IP 端口号 telnet 192.168.1.1 3306 2.如果是在aliyun或者aws云服务器上自建数据库 2.1 在安全组里开 ...
- 【SpringBoot 基础系列】实现一个自定义配置加载器(应用篇)
[SpringBoot 基础系列]实现一个自定义配置加载器(应用篇) Spring 中提供了@Value注解,用来绑定配置,可以实现从配置文件中,读取对应的配置并赋值给成员变量:某些时候,我们的配置可 ...
- 从一条数据说起——InnoDB存储数据结构
本篇博客参考掘金小册--MySQL 是怎样运行的:从根儿上理解 MySQL 先给大家讲一个故事,我刚参加工作,在一个小作坊里面当[码畜](尽管现在也是),有一天老板从我背后走过,说了一句举世震惊的话: ...
- 王颖奇 20171010129《面向对象程序设计(java)》第十一周学习总结
实验十一 集合 实验时间 2018-11-8 1.实验目的与要求 (1) 掌握Vetor.Stack.Hashtable三个类的用途及常用API: (2) 了解java集合框架体系组成: (3) ...
- lammps 学习之:系统压力太大,导致原子丢失
体系压力太大:146981.52bar,体系压强太大 会把原子挤跑 出现原子丢失的情况(lost atoms). 原子丢失: 解决方法:增大体系体积.增加z方向的距离.
- 排序算法:图解快速排序算法--不超过18行代码Python和JavaScript实现快速排序算法
快速排序有三大要素 分别是 第一:找基准值--key 第二:分区 第三:比较数字大小 先来看下快速排序流程: 基准值key选取了第一个元素78 基准值是可以任意一个元素 因为选择了最左边的数据,那么就 ...
- neo4j企业版集群搭建
一.HA高可用集群搭建 版本采用的是neo4j-enterprise-3.5.3-unix.tar.gz 1.1.集群ip规划 192.168.56.10 neo4j-node1 192.168.56 ...
- 基于hexo创建博客(Github托管)
基于hexo的博客 搭建好的博客网站 dengshuo7412.com 搭建步骤 1.依赖文件下载 Node.js 2.Hexo的安装 3.部署到Github 4.Hexo创建博客基本操作 5.Hex ...