最近在给项目组做静态检测工作,也做了一部分修复问题
由于项目代码也基本完成,功能也验证差不多了,做一做静态检测还是很有必要的。
而我通过这样的活动,也对一些细节了解更加彻底
一般来说,当我们程序出现,无符号变量与有符号变量一起运算的时候,静态检测工具会报一条警告,例如:
![](https://img-blog.csdnimg.cn/img_convert/104517ce49fe042993f39e6ff753f720.png)
这条规则来自 MISRA2004-10_1_a-3
规则上是这样描述的
“整型表达式的值不能被隐性地
转换成一个不同的底层类型。
术语“底层类型”定义为:它描述一种类型,该类型
在求一个表达式的值时得到,条件是该表达式
未进行整形提升。”
该规则检查是否使用了有符号和无符号类型之间的隐性转换。示例
void Conv1_int( ) {
unsigned int u32a, u32b;
signed int s32a, s32b;s32a = u32a; /* Violation */
s32b = s32a + u32a; /* Violation */
}
当然,像这种,大部分改是很好改的。
这里mark的目的,并不是说要怎么改,而是要知道为什么?
首先,来分析下,无符号与有符号区别。
这个简单,有符号可以表示负数,但数据范围变小了。
而无符号不能表示负数。
本身也没啥,只是定义不一样,含义不一样,说到底还是0 1 ,机器还是可以计算的
但混在一起就会产生“怪怪”的现象
举个栗子:看以下代码
int a = -11;
unsigned int b = 10;
if(a < b)
{
cout << "a < b a+b=" << a+b << endl;
}
else
{
cout << "a > b a+b=" << a+b << endl;
}
//实际输出: “a > b a+b=4294967295”
结果,肯定不是我们想要的。
这个也好理解,因为 负数 是 11111111,比一般正数都要大(至少CPU是这样理解的)
但不符合,我们原先的设想,这里是个 问题,还挺严重的
那么可以得出结论:
“有符号数和无符号数混合运算时(包括逻辑运算和算术运算)默认会将有符号数看成无符号数进行运算,返回无符号数结果”
从以上例子中,至少可以知道 + > 是符合的。
不小心,搜索了网上例子,发现有一篇文章说
有符号数和无符号数混和运算时,+-*一律转换为有符号数再进行运算,而/则转换为无符号数再进行运算(VC编译器的结果,GCC也是如此)。
那么,还需要验证下 / 这个符号,俗称 除法
int a = -10;
unsigned int b = 10;
if(a > b)
{
cout << "a > b a/b=" << a/b << endl;
}
else
{
cout << "a < b a/b=" << a/b << endl;
}
//实际输出结果: a > b a/b=429496728
//还是亲自验证下的好
这里,应该还要考虑一种情况:当两个类型大小不一致时,会先转成大类型
int a = -20;
unsigned char b = 10;
if(a > b)
{
cout << "a > b a/b=" << a/b << endl;
}
else
{
cout << "a < b a/b=" << a/b << endl;
}
cout << "a+b=" << a + b << endl;
//此时,输出
a < b a/b=-2
a+b=-10
此时,符合实际预期的,a / b, a+b 也正常了。
那么,的确,如果类型不一致的时候,会先转换成 大的类型(字节数比较多),然后再比较
严格意义上来讲,还应该再确认下:(把int 改成 char,unsigned char 改成 unsigned int)
char a = -20;
unsigned int b = 10;
if(a > b)
{
cout << "a > b a/b=" << a/b << endl;
}
else
{
cout << "a < b a/b=" << a/b << endl;
}
cout << "a+b=" << a + b << endl;
//此时输出:
a > b a/b=429496727
a+b=4294967286
又不正常了。
说明:当小类型转换成大类型的时候,符号位是不会变化的,char -> int ,unsigned 只会 unsigned
然后再套用前面,如果无符号 有符号,会先变成无符号,再比较或运算,结果还是无符号
应该清楚了,大致原理了。
最后回答下题目。
首先:是不可预期了,好在当前主流IDE都是至少是提示警告的,因此要引起重视。
其次:一般情况下,我们业务场景也有特殊,输出参数也好,参数也好,往往数据范围都是在有符号的范围内,或根本不会出现负数情况(异常除外)。
“数据不会出现负数,所以无所谓”
这个是不严谨的,代码会随着时间推移,会有变化的,比如,有其他人员参与;比如,协议更改了,增加负数一些含义,这些大于小于,很容易被忽略的
后期再来改进,再来分析,往往都是 血的教训
嗯,对,近期我们做的事情,也是因为现场有教训,才从头到尾梳理一遍。给大家瞄一眼:
![](https://img-blog.csdnimg.cn/img_convert/361184362d6afdacb562a52ae134a197.png)
结果是没有问题的
像以下几种,会存在风险,有时候都不知道怎么死的。
![](https://img-blog.csdnimg.cn/img_convert/c912918b0cd7a764082681eddecf9af3.png)
因为一个判断里面,既有变量 又有函数返回值,还有进行计算,条件而且是组合的,
所以:代码规范上是不允许的!!!
上面除了图片上红色字可能存在风险以外,还有“是否所有逻辑判断都考虑到”这个风险,不可取,会带来很大问题
![](https://img-blog.csdnimg.cn/img_convert/18c5bc38e0d17d7daf3465e4cd46093a.png)
这些代码都是来写bug的。
不要问我眼里为什么常含泪水,是因为我深(e)爱(xin)这段代码!