编写安全代码:有符号数和无符号数的移位区别右移

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

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

#include <stdlib.h>





int main ()

{

    int a = 0x80000000;

    unsigned int b = 0x80000000;



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

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



    return 0;

}
输出结果为
[root@Lnx99 test]#./a.out

a right shift value is 0xC0000000

b right shift value is 0x40000000
为什么结果不同呢?
查看汇编代码
Dump of assembler code for function main:
0x080483c4 <main+0>: push %ebp
0x080483c5 <main+1>: mov %esp,%ebp
0x080483c7 <main+3>: and $0xfffffff0,%esp
0x080483ca <main+6>: sub $0x20,%esp
0x080483cd <main+9>: movl $0x80000000,0x18(%esp)
0x080483d5 <main+17>: movl $0x80000000,0x1c(%esp)
0x080483dd <main+25>: mov 0x18(%esp),%eax
0x080483e1 <main+29>: mov %eax,%edx
0x080483e3 <main+31>: sar %edx
0x080483e5 <main+33>: mov $0x80484e4,%eax
0x080483ea <main+38>: mov %edx,0x4(%esp)
0x080483ee <main+42>: mov %eax,(%esp)
0x080483f1 <main+45>: call 0x80482f4 <printf@plt>
0x080483f6 <main+50>: mov 0x1c(%esp),%eax
0x080483fa <main+54>: mov %eax,%edx
0x080483fc <main+56>: shr %edx
0x080483fe <main+58>: mov $0x8048501,%eax
0x08048403 <main+63>: mov %edx,0x4(%esp)
0x08048407 <main+67>: mov %eax,(%esp)
0x0804840a <main+70>: call 0x80482f4 <printf@plt>
0x0804840f <main+75>: mov $0x0,%eax
0x08048414 <main+80>: leave
0x08048415 <main+81>: ret
End of assembler dump.
其中红色代码对应的是a>>1,sar为算术右移,使用符号位补位,在这里补的全是1.
蓝色代码对应的是b>>1,shr为逻辑右移,使用0补位。
 
在平时的工作中,一般情况下,我们所期待的移位操作应该为逻辑右移,所以在使用移位操作时,一定要注意操作数的类型,一定要保证为无符号数。这样结果才是我们所期待的结果。
 
查了查资料,根据大多数的说法。C标准没有规定有符号数的右移如何处理。那么对于有符号数的右移处理,就由编译器决定。
    
作者:wanglei_wan
    
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
原文地址:https://www.cnblogs.com/because/p/2711976.html