编写安全代码——小心有符号数的右移操作(转载)

简介: 作者:gfree.wind@gmail.com博客:blog.focus-linux.net     linuxfocus.
作者:gfree.wind@gmail.com
博客:blog.focus-linux.net     linuxfocus.blog.chinaunix.net

话说有这样的一段代码:
  1. #include <stdlib.h>
  2. #include <stdio.h>


  3. static void divide_by_two(int num)
  4. {
  5.     while (num) {
  6.         printf("%d\n", num);
  7.         num /= 2;
  8.     }
  9. }

  10. int main()
  11. {
  12.     int num;
  13.     scanf("%d", &num);

  14.     divide_by_two(num);

  15.     return 0;
  16. }
某天,一个刚毕业的朋友——没有贬低应届生的意思哦~~~,开始负责维护这段代码。他呢,看到num /= 2,想起课程上讲过,整数右移一位,就等于除于二,并且右移操作比除法运算要高效的多。于是将 num /=2 改为了 num = num>>1。

代码变为
  1. #include <stdlib.h>
  2. #include <stdio.h>


  3. static void divide_by_two(int num)
  4. {
  5.     while (num) {
  6.         printf("%d\n", num);
  7.         num = num>>1;
  8.     }
  9. }

  10. int main()
  11. {
  12.     int num;
  13.     scanf("%d", &num);

  14.     divide_by_two(num);

  15.     return 0;
  16. }
编译成功后,当然不能忘了测试:
  1. [xxx@xxx-vm-fc13 test]$ ./a.out
  2. 10
  3. 10
  4. 5
  5. 2
  6. 1
  7. [xxx@xxx-vm-fc13 test]$ ./a.out
  8. 3
  9. 3
  10. 1
这位朋友对于结果很满意,于是将改动提交到了服务器,下班回家~~~

结果第二天就有同事来找他,说他的程序陷入了死循环:
  1. [xxx@xxx-vm-fc13 test]$ ./a.out
  2. -5
  3. -5
  4. -2
  5. -1
  6. -1
  7. -1
  8. 。。。。。。
  9. -1
这位朋友刚参加工作,第一次提交改动,就造成了这样的结果,自然很紧张。不是右移一位就等于除以2吗?究竟是怎么回事呢?虽然暂时不知道答案,也只能将改动rollback回去。

那么到底是什么原因呢?没错,右移一位就等于除以2,但是这里需要加一个条件,这里指的是正数。而对于有符号整数,且其值为负数时,在C99标准中对于其右移操作的结果的规定是implementation-defined.

在Linux上的GCC实现中,有符号数的右移操作的实现为使用符号位作为补充位。因此-1的右移操作仍然为0xFFFFFFFF。这导致了死循环。
目录
相关文章
|
3月前
【编程基础知识】正数负数的二进制位运算(左移 右移 无符号右移)
正数和负数需转换成二进制后进行移位运算。左移低位补0,不影响符号位;右移符号位跟随移动,最高位还原为原符号位;无符号右移高位补0,适用于负数处理。
199 0
|
8月前
|
存储 C语言
在C语言中编写,用于从键盘接收输入的整数并判断该数是否能被3整除
在C语言中编写,用于从键盘接收输入的整数并判断该数是否能被3整除
204 0
|
8月前
|
C语言
C语言自增减、逻辑运算、位运算、位移运算及三目运算操作
C语言自增减、逻辑运算、位运算、位移运算及三目运算操作
59 0
C语言十六弹 --求两个整数二进制位不同的位数
C语言十六弹 --求两个整数二进制位不同的位数
|
8月前
|
C语言
C语言第四十弹---两个整数二进制位不同的个数
C语言第四十弹---两个整数二进制位不同的个数
|
存储 人工智能 编译器
C语言之(有关%d和%u的有关内容,输出方法)(有符号和无符号在内存中的存储情况)(整形无符号数和有符号数是如何进行计算的,整形无符号数和有符号数在循环中的应用举例)
C语言之(有关%d和%u的有关内容,输出方法)(有符号和无符号在内存中的存储情况)(整形无符号数和有符号数是如何进行计算的,整形无符号数和有符号数在循环中的应用举例)
532 0
|
C语言
C语言:写一个代码,使用 试除法 打印100~200之间的素数(质数)-2
思路二: 总体思路: 因为偶数除了 2 都不是素数,且题目范围中没有 2 , 所以可以只生成 100~200 之间的奇数,可以排除一半的数字, 效率提升一倍。
130 0
|
C语言
C语言:写一个代码,使用 试除法 打印100~200之间的素数(质数)-1
思路一:使用试除法 总体思路: (一). 使用外循环:生成 100~200 之间的数。 (二). 设置内循环:生成 2 ~ i-1 的数。
132 0
算数右移和逻辑右移的区别及逻辑运算的窍门
算数右移和逻辑右移的区别及逻辑运算的窍门
957 0
|
机器学习/深度学习 存储 人工智能

热门文章

最新文章