C4146报错原因分析
来源:互联网 发布:詹姆斯本赛季盖帽数据 编辑:程序博客网 时间:2024/06/13 20:35
C4146报错原因分析
标签(空格分隔): C++ C4146 一元负运算符应用于无符号类型,结果仍为无符号型
- C4146报错原因分析
- 事发现场
- 翻车过程
- 翻车原因
- 老司机如是说
- 番外篇
事发现场
#include <iostream>#include <limits.h>int test(long long int);int main(void){ long long int n = --2147483648; int a = getLength(n); std::cout << a << '\n'; cin.get(); return 0;}int test(long long int x){ if (x>INT_MAX || x<INT_MIN) { std::cout << " test 输入的参数不在合理的范围内,请输入一个int值!" << '\n'; } return 0;}
error C4146:一元负运算符应用于无符号类型,结果仍为无符号型
翻车过程
在小司机的机器上,INT_MAX
的数值为2147483647
,INT_MIN
的数值为-2147483648
。于是乎,小司机为了保证后续代码不出错,在test
函数的刚开始对形参进行了一次检查,希望将非法的数值剔除,并给予一些友(mei)好(yong)的提示信息。
为了避免实参转到形参的时候发生自动转化,于是小司机将形参的范围放大到了long long int
,信心满满的将代码写完之后进行了测试,实参在-2147483647~2147483647
的范围内都没有输出提示信息;当实参大于2147483647
之后,程序按照预先的想法输出了提示信息;但是当实参小于等于-2147483648
之后,却出车祸了。程序并没有按照小司机预想那样运行,而是输出了:
。。。。。
于是乎小司机陷入了沉思,
于是乎,小司机又试了一下这个代码:
#include <iostream>int main(void){ long long int n = -2147483648; cin.get(); return 0;}
然后,还是 。。。。。至此,小司机已经彻底疯了。
翻车原因
首先要明确的是:
2147483647 :0111 1111 1111 1111 1111 1111 1111 1111
-2147483647:1111 1111 1111 1111 1111 1111 1111 1111
-2147483648:1000 0000 0000 0000 0000 0000 0000 0000
- 从二值化数据来看的增长顺序为0,1,~,2147483647,-2147483648,-1,-2,~,-2147483647。
- 宇宙最强IDE
VS2017
在看到-2147483648的时候,首先判断2147483648 > INT_MAX,知道int装不下,于是决定使用 unsigned int。然后发现前面还有个负号,于是再对2147483648取反,最强IDEVS2017
就认为已经将这个数字变成了负数,但是2147483648取反还是2147483648,这就出现了一元负运算符应用于无符号类型,结果仍为无符号型
这个错误。在以前的VS
中,这个只是一条warning
,但是在新版本的VS
中,这个已经升级为了error
,这对开发者来说无疑是一个好事,因为原来的操作会将形参-2147483648
直接变成2147483648
而且只说一声warning
,实在是太邪恶了。 - 但我目前还是很不解的就是明明在第二次测试的时候,已经事先声明了
long long int
,结果宇宙最强IDEVS2017
还是会报错,这可能也就不能怪IDE了,也许就是这么设定的也没准。但是小司机要是就是想在屏幕上看见一个-2147483648
怎么办呢?
老司机如是说
首先抛出方法:
//方法一#include <iostream>int main(void){ int n = -2147483648LL; std::cout << n << '\n'; cin.get(); return 0;}
方法一使用 LL 来让VS
知道你输进来的数是一个long long
型的,之后再强行塞进int
类型就可以了。
//方法二#include <iostream>int main(void){ int n = -2147483647; std::cout << n-1 << '\n'; cin.get(); return 0;}
方法二使用算式来规避边界的判断。
番外篇
如果我们使用cin
来进行n
的赋值,那么-2147483648是可以被直接正确录入的。(这还差不多)
int main(void){ // int n = -2147483647; // -2147483648 在vs上无法直接赋值,但是在atom上可以直接编译通过并运行 int n; std::cout << " 请输入一个int大小的数值 " << '\n'; std::cin >> n; std::cout << n << '\n'; cin.get(); return 0;}
- C4146报错原因分析
- Android查询电话薄报错原因分析
- Android调用webService报错原因分析
- Python报错信息与原因分析
- MySQL server has gone away报错原因分析
- MySQL server has gone away报错原因分析
- MySQL server has gone away报错原因分析
- iOS 绘图时使用 UIGraphicsGetCurrentContext() 报错的原因分析
- MySQL server has gone away报错原因分析
- MySQL server has gone away报错原因分析
- Xcode6编译SDWebImage报错原因分析(SDWebImageDownloaderOperation.m错误)
- MySQL server has gone away报错原因分析
- MySQL server has gone away报错原因分析
- tomcat启动报错原因分析及解决
- AlertDialog传递application context报错原因分析
- Eclipse打包apk报错原因分析(一)
- 分析ArrayList在遍历时修改报错的原因
- g++编译报错原因分析expected type-specifier before
- 路虎中DS1协议
- 获取数据库最后一条数据
- python实现12306验证和登录
- C++ 实现反射
- C#访问修饰符总结
- C4146报错原因分析
- windows磁盘备份还原
- REST简介
- solr 6.3.0 使用实例
- Java语言规范基于JavaSE9 第七章 包和模块(一)
- C#不能打开excel文件
- struts2_day02_07-在action操作域对象
- AOP相关资料网址
- Activity嵌套多个Fragment实现不同全屏模式状态栏