美文网首页C/C++经验技巧总结
使用无符号类型要特别注意

使用无符号类型要特别注意

作者: XDgbh | 来源:发表于2018-01-14 23:30 被阅读2次

    一个由无符号类型引发的微妙的错误

    #include <stdio.h>  
    #include  <string.h>
    
    int main()
    {
        char array[] = "hello";
        int d = -1, x;
        //(1)//if (d <= sizeof(array) / sizeof(char))    
        //(2)//if (d <= strlen(array))
    
        //if (d <= (int)sizeof(array) / sizeof(char))    /*输出:x = 104*/     
        if (d <= (int)strlen(array))        /*输出:x = 104*/
        {
            x = array[d + 1];
            printf("x = %d\n", x);  //字符'h'对应的ASCII码是104,   'a'是97
        }
        else
        {
            printf("sizeof(array) / sizeof(char) = %u\n", sizeof(array) / sizeof(char));
            printf("strlen(array) = %u\n", strlen(array));  
          //用%d输出也是一样,都是正数
        }
    
        return 0;
    }
    
    • 这个程序若用(1)或(2)的判断条件会输出:
      sizeof(array) / sizeof(char) = 6
      strlen(array) = 5
      加上强制类型转换(int)才会输出:x = 104

    (1)原因是sizeof操作符(注意它不是一个函数,也可以有 sizeof char;sizeof(char);效果一样)的返回值类型是size_t,而typedef unsigned int size_t;
    所以在执行表达式d <= sizeof(array)/sizeof(char)时,右边表达式结果为无符号整型6,因此会将左边的整型d装换成无符号整型(-1(在计算机中以1的补码形式存在为二进制1111...11111)将变成变成一个超级大的整数),因此判断结果是false。

    改正方法:d <= (int)sizeof(array)/sizeof(char),人为增加强制类型转换,这样就不必由编译器来选择结果的类型了。

    (2)同理,strlen()函数的返回值类型也是size_t,而typedef unsigned int size_t;。但是注意strlen()函数和sizeof操作符的区别,sizeof会多计算一个结束符'\0'的大小,因此会多1,而strlen()函数总是只计算实际字符串字符个数。

    改正方法:d <= (int)strlen(array),人为增加强制类型转换,这样就不必由编译器来选择结果的类型了。

    对无符号类型的建议(《C专家编程》第24页)

    1、尽量不要在代码中使用无符号类型,以免增加不必要的麻烦,尤其是,不要仅仅因为无符号类型不存在负值(如年龄)而用它来表示数量,可以多增加if-else判断数量的合法性也比用无符号类型更安全。否则一个int的 -1,由编译器自动升级成无符号型int,将会变成一个非常大的数。
    2、如果用了,应该在表达式中使用强制类型转换,使操作数均为有符号或者无符号类型,这样就不必由编译器来选择结果的类型,可以避免微妙的错误发生。
    3、只有在使用位段和二进制掩码时,最好去用无符号数。这里就要谈到正数和负数在计算机中的二进制存储方式了。正数简单,就是原码二进制形式存储,如int型32bit位 int a = 1;那么a在计算机中存储为二进制000...(总共31个0)...0001。但是负数就比较复杂,要用原码求反码再加1得到的补码的二进制形式存储在计算机中,如int b = -1;原码和a一样,反码就是111...(总共31个1)...1110,然后反码加1得到补码111...(总共32个1)...1111。可见b并不是简单的存储为二进制100...(总共30个0)...0001。因此在使用位段和二进制掩码这些需要按bit位操作的情况下,为了在使用时让我们脑子里想的和计算机处理的一致,尽量都用无符号类型,就可以避免负数在计算机中的特殊存储方式带来的影响。
    《注意:负数要以10进制输出时,又要将计算机中存储的补码,先减1求得反码,再按位求反得到原码,然后将原码转换成10进制输出并在前面添加一个‘-’号》

    使用无符号类型的优缺点

    • 比如int类型和unsigned int类型,同样是占用4字节(32bit位),int类型的取值范围是(-2^31到2^31),而unsigned int类型的取值范围是(0到2^32),可见在利用正数的这一半时无符号数的可用范围是有符号的两倍。有符号数最高bit位的0或1只能表示+-符号,不能表示数值,浪费了。

    相关文章

      网友评论

        本文标题:使用无符号类型要特别注意

        本文链接:https://www.haomeiwen.com/subject/lunloxtx.html