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的数值为2147483647INT_MIN的数值为-2147483648。于是乎,小司机为了保证后续代码不出错,在test函数的刚开始对形参进行了一次检查,希望将非法的数值剔除,并给予一些友(mei)好(yong)的提示信息。
为了避免实参转到形参的时候发生自动转化,于是小司机将形参的范围放大到了long long int,信心满满的将代码写完之后进行了测试,实参在-2147483647~2147483647的范围内都没有输出提示信息;当实参大于2147483647之后,程序按照预先的想法输出了提示信息;但是当实参小于等于-2147483648之后,却出车祸了。程序并没有按照小司机预想那样运行,而是输出了:

image_1c089t91spsq2s8g7h1k5q17e89.png-4.4kB 。。。。。
于是乎小司机陷入了沉思,tm之前也没见过这种错误啊。。。。

于是乎,小司机又试了一下这个代码:

#include <iostream>int main(void){    long long int n = -2147483648;    cin.get();    return 0;}

然后,还是image_1c089t91spsq2s8g7h1k5q17e89.png-4.4kB 。。。。。至此,小司机已经彻底疯了。


翻车原因

首先要明确的是:

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。
  • 宇宙最强IDEVS2017在看到-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;}

原创粉丝点击