一、问题描述
warning信息:warning: comparison between signed and unsigned integer expressio, 有符号/无符号不匹配
c++编译环境:centos7 + g++或者vs2015
c++代码举例:
#include<iostream>
#include<bitset>
using namespace std;
int main()
{
int x = -8;
unsigned y = 7;
if (x > y) {
cout << x << endl;
}
else {
cout << y << endl;
}
cout << "x = " << x << endl;
cout << "x 二进制 " << bitset<32>(x) << endl;
cout << "y = " << y << endl;
cout << "y 二进制 " << bitset<32>(y) << endl;
cout << endl;
cout << "unsigned(x) = " << unsigned(x) << endl;
cout << "unsigned(x) 二进制 " << bitset<32>(unsigned(x)) << endl;
cout << "unsigned(y) = " << unsigned(y) << endl;
cout << "unsigned(y) 二进制 " << bitset<32>(unsigned(y)) << endl;
cout << endl;
cout << "x + y = " << x + y << endl;
cout << "x + y 二进制 " << bitset<32>(y + x) << endl;
cout << "signed(x + y) = " << signed(x + y) << endl;
cout << "signed(x + y) 二进制 " << bitset<32>(signed(x + y)) << endl;
system("pause");
return 0;
}
在涉及到有符号数和无符号数的比较时,c++的语法允许这样的比较,但是在编译的过程中会有warning提示。
一般来说很多人都不会刻意的去处理warning,而只是在有error的时候才认真修改bug,直到吃过n次亏之后才知道warning也是个不小的隐患。像有符号数和无符号数的比较这种问题经常会在循环遍历容器的时候使用到,
例如for(int i=0;i<arr.size();i++)
,其中int是有符号数,arr.size()返回的size_type是无符号数。
在某些情况下,该warning会成为一个直接影响程序功能的bug!
以上面代码为例子,-8和7比较大小的结果输出的是:
-8竟然大于7,这搁谁受得了啊!这要是换一个循环什么的逻辑,你能想到是因为这个出错吗?
保护头发,从我做起,读一读本文让你深刻的记住这个隐藏的bug,这波你血赚不亏!
二、问题分析
1、有符号数与无符号数的存储
数据存储在计算机中采取的都是二进制编码存储,c++采取的是二进制补码,正数的二进制码就是它的二进制补码,负数的绝对值的二进制码按位取反再加一就是它的补码。
- 举例子
cout << bitset<32>(1) << endl;//补码:00000000000000000000000000000001
cout << bitset<32>(-1) << endl;//补码:11111111111111111111111111111111
那么再来看一下-8和7的数据存储,一个发现就是无论是有符号数还是无符号数他们的二进制编码是一样的,不过signed将二进制编码的首位视为符号位,unsigned则没有符号位一说,所以输出的结果就如例子中一样有了差距。总结起来就是,读取的是同一个编码却有了不同的理解和翻译。
int x = -8;
unsigned y = 7;
cout << "x = " << x << endl;
cout << "x 二进制 " << bitset<32>(x) << endl;
cout << "y = " << y << endl;
cout << "y 二进制 " << bitset<32>(y) << endl;
cout << endl;
cout << "unsigned(x) = " << unsigned(x) << endl;
cout << "unsigned(x) 二进制 " << bitset<32>(unsigned(x)) << endl;
cout << "unsigned(y) = " << unsigned(y) << endl;
cout << "unsigned(y) 二进制 " << bitset<32>(unsigned(y)) << endl;
cout << endl;
- 输出结果
2、有符号数与无符号数的运算
在c++的运算中,signed会被转化为unsigned。-8如果被当做unsigned参与运算的话自然而然的就会变成数字4294967295,所以运算得到的结果也就不可能正确了。
cout << "x + y = " << x + y << endl;
cout << "x + y 二进制 " << bitset<32>(y + x) << endl;
cout << "signed(x + y) = " << signed(x + y) << endl;
cout << "signed(x + y) 二进制 " << bitset<32>(signed(x + y)) << endl;
回到一开始提到的+7和-8的大小比较,结果输出的是-8也就是由于在无符号的情况下,-8变成了4294967295远大于7。
至此,原因分析over。
三、解决方案
1.都使用unsigned 类型。
2.或者评估实际运行中值的范围,仅使用安全范围内(UINT_MIN~INT_MAX)的值。
❤️❤️❤️ 给你一个有爱的眼神,看过本文千万不要忘了点赞、关注、收藏哦!灰常感谢! ❤️❤️❤️