无符号有符号一起运行,会带来哪些风险?

最近在给项目组做静态检测工作,也做了一部分修复问题

由于项目代码也基本完成,功能也验证差不多了,做一做静态检测还是很有必要的。

而我通过这样的活动,也对一些细节了解更加彻底

一般来说,当我们程序出现,无符号变量与有符号变量一起运算的时候,静态检测工具会报一条警告,例如:

 

 这条规则来自 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都是至少是提示警告的,因此要引起重视。

其次:一般情况下,我们业务场景也有特殊,输出参数也好,参数也好,往往数据范围都是在有符号的范围内,或根本不会出现负数情况(异常除外)。

“数据不会出现负数,所以无所谓”

这个是不严谨的,代码会随着时间推移,会有变化的,比如,有其他人员参与;比如,协议更改了,增加负数一些含义,这些大于小于,很容易被忽略的

后期再来改进,再来分析,往往都是 血的教训

嗯,对,近期我们做的事情,也是因为现场有教训,才从头到尾梳理一遍。给大家瞄一眼:

 

   结果是没有问题的

像以下几种,会存在风险,有时候都不知道怎么死的。

 

 因为一个判断里面,既有变量 又有函数返回值,还有进行计算,条件而且是组合的,

所以:代码规范上是不允许的!!!

上面除了图片上红色字可能存在风险以外,还有“是否所有逻辑判断都考虑到”这个风险,不可取,会带来很大问题

 

这些代码都是来写bug的。

不要问我眼里为什么常含泪水,是因为我深(e)爱(xin)这段代码!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值