无符号数与有符号数之间的运算

问题

运行如下代码

int i = 10;
unsigned u = 20;
cout << i - u << endl;  //输出4294967286

i -= u;
cout << i << endl;      //输出-10

第一次cout输出4294967286,而第二行输出-10,为什么会有这种现象呢?

在运算i - u时,编译器会先将i强转为unsigned类型,然后再进行运算,两个unsigned类型进行运算,且结果是一个“负值”,自然会产生溢出。

而第二行是i -= u可展开为i = static_cast<int>(i - u)4294967286强转为int类型后为-10,其结果自然就正确了,不过此过程中仍存在溢出,虽然相当隐晦,但若是测试项目中开启了ubsan,这行语句就会被检测并触发crash,应当极力避免!

解决方式

i -= static_cast<int>(u);

不过注意,此过程中将u强转为int类型也存在溢出风险,需自行判断数据范围是否可能导致溢出。

引申

int类型和unsigned类型之间的所有操作符中:加减乘除甚至比较符,均会先将int强转为unsigned再做运算。

位操作符不会有此现象。

取余操作虽不会溢出,但结果会不合预期,原因可能与有符号数和无符号数不同的存储方式有关,具体原因待分析:

unsigned u = 3;
int i = -10;
int i2 = 3;
cout<<(i % i2)<<endl; //输出-1
cout<<(i % u)<<endl;  //输出0