C陷阱篇之有/无符号数混合时自动类型转换

本文探讨了C语言中有符号和无符号数混合运算可能导致的陷阱。当无符号数与有符号数进行计算时,编译器会将所有操作数转换为无符号类型,可能导致预期之外的结果。例如,即使`i`的值为8,如果与-1比较,`i>=-1`也会判断为假,因为-1被转换成了一个大整数。作者通过示例代码强调了理解这种自动类型转换的重要性,并给出了避免这类错误的建议,包括显式指定类型、谨慎使用unsigned类型以及必要时进行强制类型转换。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    先看下面代码:

    void main()

    {

      unsigned int i=8;

      if(i>=-1)  printf("8>=-1\n");

      else  printf("8<-1");

    }

    输出结果是8<-1,明明赋值为8的变量i,结果被程序判定比-1还小,这是怎么回事?

    问题根源在于变量i定义中的unsigned我们都知道,int/short/char等类型分signedunsigned。C的表达式中signedunsigned混合运算有三种情况:a.操作数全为signed;b.操作数全为unsigned;c.操作数混合了signedunsigned。前两种情况,相同符号操作没什么问题,可情形c.涉及不同符号间的混合计算就要注意,编译器会自动对操作数进行规整化:只要表达式中存在一个无符号数,所有操作数都被转化为无符号数,运算按相应无符号操作符进行,计算结果也是一个无符号数

    因此作为混合符号运算,上例if(i>=-1)中,无符号的i使原本默认有符号的-1被转换成无符号的大整数,判断条件就不成立。类似情况很多,例如下面常见的笔试题:

    void foo(void)

    {

      unsigned int a = 6;

      int b = -20;

      (a+b > 6) ? puts("> 6") : puts("<= 6");

    }

    这也是考查应试者是否了解符号自动规整原则:a为无符号数,a+b时编译器把b也转换成一个无符号整数,这样a+b的结果大于6,而不是想当然的-14以上两个例子还有迹可寻,可下面这个就:

    void main()

    {

      int x = 2;

      char * str = "abcd";

      int y = (x - strlen(str) ) / 2;

      printf("%d\n",y);

    }

    结果是-1吧?No,实际输出2147483647。因为大家容易忽略一点,strlen返回值类型size_tunsigned int的重定义(有人注意过么?),这样strlen的无符号返回值进入表达式,使原本有符号的x,y都被自动转换成无符号。

结论

    隐含的符号自动转换是一大陷阱。特别是数值运算类程序中,一旦混用有符号/无符号数,甚至说只要使用了unsigned及其重定义类型,都有可能发生错误,要加倍小心!

    为防止意外转换,一方面要显式指定类型,不要用int,char这种缺少提示的中性表示法,这种含糊的表示用多了,会本能地忽略和回避符号问题;另一方面要谨慎选用unsigned型,不要仅仅因为无符号数没有负值就用它表示数量,比如有人喜欢用unsigned int定义for/while循环计数量,这很不安全,一不小心在循环内和负数做比较,就会发生逻辑错误或死循环;最后,如果非要让unsigned型参与计算,可以用强制类型转换保证中间操作数和结果为signed

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值