C/C++经验技巧总结

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

2018-01-14  本文已影响2人  XDgbh

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

#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)原因是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进制输出并在前面添加一个‘-’号》

使用无符号类型的优缺点

上一篇下一篇

猜你喜欢

热点阅读