Chinaunix首页 | 论坛 | 博客
  • 博客访问: 7376623
  • 博文数量: 159
  • 博客积分: 10424
  • 博客等级: 少将
  • 技术积分: 14605
  • 用 户 组: 普通用户
  • 注册时间: 2010-07-14 12:45
个人简介

啦啦啦~~~

文章分类
文章存档

2015年(5)

2014年(1)

2013年(5)

2012年(10)

2011年(116)

2010年(22)

分类: C/C++

2011-05-31 16:08:31

本文的copyleft归gfree.wind@gmail.com所有,使用GPL发布,可以自由拷贝,转载。但转载请保持文档的完整性,注明原作者及原链接,严禁用于任何商业用途。
作者:gfree.wind@gmail.com
博客:linuxfocus.blog.chinaunix.net
    

(下面所有的测试为Linux平台,gcc编译器)
  1. #include <stdio.h>
  2. #include <stdlib.h>


  3. int main ()
  4. {
  5.     int a = 0x80000000;
  6.     unsigned int b = 0x80000000;

  7.     printf("a right shift value is 0x%X\n", a >> 1);
  8.     printf("b right shift value is 0x%X\n", b >> 1);

  9.     return 0;
  10. }
输出结果为
  1. [root@Lnx99 test]#./a.out
  2. a right shift value is 0xC0000000
  3. b right shift value is 0x40000000
为什么结果不同呢?
查看汇编代码
  1. Dump of assembler code for function main:
  2. 0x080483c4 : push %ebp
  3. 0x080483c5 : mov %esp,%ebp
  4. 0x080483c7 : and $0xfffffff0,%esp
  5. 0x080483ca : sub $0x20,%esp
  6. 0x080483cd : movl $0x80000000,0x18(%esp)
  7. 0x080483d5 : movl $0x80000000,0x1c(%esp)
  8. 0x080483dd : mov 0x18(%esp),%eax
  9. 0x080483e1 : mov %eax,%edx
  10. 0x080483e3 : sar %edx
  11. 0x080483e5 : mov $0x80484e4,%eax
  12. 0x080483ea : mov %edx,0x4(%esp)
  13. 0x080483ee : mov %eax,(%esp)
  14. 0x080483f1 : call 0x80482f4
  15. 0x080483f6 : mov 0x1c(%esp),%eax
  16. 0x080483fa : mov %eax,%edx
  17. 0x080483fc : shr %edx
  18. 0x080483fe : mov $0x8048501,%eax
  19. 0x08048403 : mov %edx,0x4(%esp)
  20. 0x08048407 : mov %eax,(%esp)
  21. 0x0804840a : call 0x80482f4
  22. 0x0804840f : mov $0x0,%eax
  23. 0x08048414 : leave
  24. 0x08048415 : ret
  25. End of assembler dump.
其中红色代码对应的是a>>1,sar为算术右移,使用符号位补位,在这里补的全是1.
蓝色代码对应的是b>>1,shr为逻辑右移,使用0补位。

在平时的工作中,一般情况下,我们所期待的移位操作应该为逻辑右移,所以在使用移位操作时,一定要注意操作数的类型,一定要保证为无符号数。这样结果才是我们所期待的结果。

查了查资料,根据大多数的说法。C标准没有规定有符号数的右移如何处理。那么对于有符号数的右移处理,就由编译器决定。

阅读(7580) | 评论(8) | 转发(9) |
给主人留下些什么吧!~~

GFree_Wind2012-03-21 16:38:13

TestForCU: 这个例子给我误导了。。。呵呵!
int a = 0x80000000;  //有符号的十进制的0吧
unsigned int b = 0x80000000;//明确说明了是无符号数,就是除以2了
所以用十六进.....
int  a = 0x80000000并不是0,而是-2147483648。
过程为-2^(31)+0(即除符号位的值)

TestForCU2012-03-21 14:07:22

这个例子给我误导了。。。呵呵!
int a = 0x80000000;  //有符号的十进制的0吧
unsigned int b = 0x80000000;//明确说明了是无符号数,就是除以2了
所以用十六进制去写一个数时,在你定义数据类型时他就会给出不同的解释。。
我们习惯用十进制来写一个数,而最终在机器中表现的二进制的补码
这觉得这题还可以这样弄。
//    unsigned char i;
//   char i;
       i = 0x82;
    //unsigned char i; i = -126;-126就是0x82,没有人会这样写吧。。呵呵
   // printf("%x",i);
   // printf("%d&

GFree_Wind2011-06-01 23:13:46

yifangyou: 问题是左移的时候是不是一样,会把有符号的正数变为负数?.....
左移都是使用逻辑左移。有符号的正数自然可能会变成负数。

yifangyou2011-06-01 21:49:40

问题是左移的时候是不是一样,会把有符号的正数变为负数?

GFree_Wind2011-06-01 00:12:19

zhangyd6: 负数使用补码来表示,右移的是算数运算,应该使用1填充。.....
我的意思是说,标准中是否明确说明有符号数使用算术右移