【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 ...
随机推荐
- 数学--数论--整除分块(巨TM详细,学不会,你来打我)
1.概念 从一道例题说起 在介绍整除分块之前,我们先来看一道算数题:已知正整数n,求∑i=1n⌊ni⌋已知正整数n,求∑i=1n⌊ni⌋在介绍整除分块之前,我们先来看一道算数题: 已知正整数n,求∑i ...
- unittest 管理用例生成测试报告
# 登录方法的封装 from appium import webdriver from time import sleep from python_selenium.Slide import swip ...
- jdbc连接mysql数据库 (idea)
mysql我们已经不再陌生,但是通过Java来操作数据库的增删改查,我们就需要用到jdbc来连接: 我们使用idea来连接数据库,首先:我们电脑上需要安装idea和mysql,之后在网站上登录MySQ ...
- spring Code(spring 核心)
一.spring的作用 spring 就是为了让我们以后能够做大的项目准备的.spring核心的功能就是一个工厂模式,spring相当于为你的项目专门成立一个一个工厂,这个工厂负责创建对象 ,维护对象 ...
- LeetCode--Sort Array By Parity && N-Repeated Element in Size 2N Array (Easy)
905. Sort Array By Parity (Easy)# Given an array A of non-negative integers, return an array consist ...
- Nacos系列(一):Nacos环境安装及Hello World示例
现在微服务架构越来越火,微服务架构中比较重要的一项就是配置中心, Nacos是阿里巴巴的一个开源项目,它的其中一个功能就是可以作为配置中心,实现配置的动态变更.历史版本对比.配置回滚等功能. 更多的描 ...
- 自定义IDOC
目录 1需求场景 4 2配置发送端IDOC 4 2.1定义段(WE31) 4 2.2定义基本类型(WE30) 4 2.3定义消息类型(WE81) 5 2.4定义传输结构 ...
- Android如何设置只有边框背景透明的背景呢?
很简单,只需要新建一个 drawable 文件 <?xml version="1.0" encoding="utf-8"?> <shape x ...
- 排序算法:图解快速排序算法--不超过18行代码Python和JavaScript实现快速排序算法
快速排序有三大要素 分别是 第一:找基准值--key 第二:分区 第三:比较数字大小 先来看下快速排序流程: 基准值key选取了第一个元素78 基准值是可以任意一个元素 因为选择了最左边的数据,那么就 ...
- python爬虫-直播吧
概述 这是一个我很喜欢的小网站,想了解这个网站先从爬虫开始,爬取直播吧所有的栏目及内容,再存入数据库.先写个简单点的,后期再不断的优化下. 准备阶段 直播吧网址https://www.zhibo8.c ...