zoukankan      html  css  js  c++  java
  • 有符号数与无符号数比较的坑

    前言

    在c/c++ 的项目编译时经常会遇到 “comp.c:59:42: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]” 这种错误。作为一个”合格的程序员“ 对这种编译告警,通常的处理是忽略,毕竟大家一致的观点是:只有“warning”不算问题!

    下面给出一个小case:

    #include <stdio.h>
    
    int sum_elements(int a[], unsigned int length)
    {
            int i;
            int result = 0;
            for (i = 0; i <= length-1; i++)
                    result += a[i];
            return result;
    }
    
    int main(int argc, char *argv[])
    {
            int a[] = {1, 2, 3};
            int m = sum_elements(a, 0);
            printf("%d
    ", m);
            return 0;
    }
    

     一路轻车熟路,编译运行,但是得到了一个段错误。。。

    root@HF-LEE:/mnt/c/Users/Q/Desktop# g++ -Wall -g aaa.c -o aaa
    aaa.c: In function ‘int sum_elements(int*, unsigned int)’:
    aaa.c:7:43: warning: comparison between signed and unsigned integer expressions [-Wsign-compare]
                                 for (i = 0; i <= length-1; i++)
                                             ~~^~~~~~~~~~~
    root@HF-LEE:/mnt/c/Users/Q/Desktop# ./aaa
    Segmentation fault (core dumped)
    root@HF-LEE:/mnt/c/Users/Q/Desktop#
    

     这里发生了什么呢,看代码只有一个数组,那必然是越界了!!!(问题分析参考:https://www.cnblogs.com/idorax/p/6881996.html)老鸟都会在这里加上强制类型转换来解决问题。但是问题解决了,下次呢,下次还是会有这样的问题存在!所以我们需要了解下问题的本质,以及如何避免。

    沿用知乎里常用的一句话:“先问是不是,在问为什么?”

    无符号数带来的问题:

      如前面示例所示,无符号数与有符号数比较时带来的问题是最容易忽略的,也有可能是最致命的。如果循环中出现无符号数可能会引起死循环,数组中出现无符号可能会导致数组越界。这当然不能把问题归咎于无符号数,更应该说是有符号数带来的思维定势引起的问题。

      无符号数带来的问题通常是在数值比较时,与无符号数溢出时才会体现。分别是默认的类型转换与边界条件检测不正确导致的。

      既然无符号会有问题,那么我们是不是可以抛弃呢??? 你可以采用java那套做法,在习惯上从不使用无符号数(java有这种方案),但是你会在默写特定场景遇到问题:如网络编程,串口读写。。。

    如何合理的使用无符号数:

      这是问题的核心了!下面是我总结的一些内容

      1. 在位运算、模运算、回绕溢出利用较多的算法实现中(比如各种加密学算法、编码、压缩算法等)

    有符号数的符号位在进行位运算时候会造成一些迷惑,位运算中如果采用无符号数会大大减少处理问题时对语言上的思考,可以更专心关注实际问题。

      2. 在网络收发,串口读写时候使用无符号数

    TCP/IP 经常遇到无符号数,比如IP的表示,我们可以用 ip2long 把点分十进制 ip 转成一个 unsigned int 来表示,这会带来很大方便。串口读写的流更多的是用 unsigned char ,最常见的一个问题是 unsigned char 可以避免日志输出时候按照有符号输出造成的 ‘0xff’ 迷惑人的前缀。

      3. 避免有符号数与无符号数的直接接触,包括比较,运算

    无符号数与有符号数比较时,编译器会发出警告。同时编译器内部也存在一套默认的类型转换规则(编译器自动进行,用户无感知)。大致分为3类(如有错误请指正)(说明:在计算机里,负数使用反码表示的)

      先顶一下规则:有符号(int),无符号(unsigned int),非无符号(除 int 与 unsigned int外的类型,如char,unsigned char),非有符号(与前面同理)。

      有符号与无符号比较:有符号数会转换成无符号数来进行比较(如int 与 unsigned int 比较,int 转换成 unsigned int)。

      有符号与非无符号数比较:非无符号转化成有符号(如int 与 unsigned char比较,unsigned char 转换成 int)。

      无符号与非有符号数比较:非有符号转化成有符号(如unsigned int 与 char比较,char 转换成 unsigned int)。

      4. 不要只因为某个数不可能为负就用无符号数

    因为这虽然看起来很合要求,但是当无符号溢出时候带来的问题却很可能致命。

  • 相关阅读:
    Chrome V75V76新版无法存为mhtml格式解决办法
    RHEL7 的注册
    JQuery淡入淡出 banner切换特效
    怎样把小坚果做成大生意
    黄页前台联动菜单修改时不能显示,要重新选择|没样式
    V9任何页面GET调用内容分页的说明
    phpcms v9 自定义伪静态的分页函数
    phpcms v9 自定义分页 带下拉跳转
    discuz X2.5自己写代码,获取当前登录的用户信息
    discuz!X2.5技术文档
  • 原文地址:https://www.cnblogs.com/sinpo828/p/10943157.html
Copyright © 2011-2022 走看看