论坛: 编程破解 标题: C语言位运算问题-已解 复制本贴地址    
作者: kert_t8 [kert_t8]    论坛用户   登录
下面这段代码:
代码:

int a = 0xfffffff0;
int b = 0x0ffffff0;
printf("Sizeof int:%d\n", sizeof(a));
printf("a:%08X\t\tb:%08X\n", a, b);
a=a<<1;
b=b<<1;
printf("a:%08X\t\tb:%08X\n", a, b);
a=a>>1;
b=b>>1;
printf("a:%08X\t\tb:%08X\n", a, b);


的运行结果是:
引用:

Sizeof int:4
a:FFFFFFF0              b:0FFFFFF0
a:FFFFFFE0              b:1FFFFFE0
a:FFFFFFF0              b:0FFFFFF0



很明显,右移的结果对a是移了一个1进来,而b是移了一个0进来。为什么会有这样的差别?它怎么会记得移出去的是什么?难道一个寄存器不是32位的?


[此贴被 月之御者(kert_t8) 在 12月20日19时31分 编辑过]

地主 发表时间: 06-12-20 19:09

回复: kert_t8 [kert_t8]   论坛用户   登录
明白了
这是算数左移和逻辑左移的区别
下面这段代码与上面这段代码对比运行就能知道区别:
代码:

int a = 0xffffffff;
int b = 0x0ffffff0;
printf("Sizeof int:%d\n", sizeof(a));
printf("a:%08X\t\tb:%08X\n", a, b);
a=(unsigned)a<<1;
b=(unsigned)b<<1;
printf("a:%08X\t\tb:%08X\n", a, b);
a=(unsigned)a>>1;
b=(unsigned)b>>1;
printf("a:%08X\t\tb:%08X\n", a, b);



B1层 发表时间: 06-12-20 19:28

回复: SysHu0teR [syshunter]   版主   登录
是的,算术左移和逻辑左移是一样的,而算术右移和逻辑右移则不同,算术右移对高位为1的(负数)做符号位扩展。


B2层 发表时间: 06-12-20 20:28

回复: kert_t8 [kert_t8]   论坛用户   登录
左移也不同,凡是算数移位都是以上一位做填充的
比如1001 算数左移就是0011 算数右移就是1100 逻辑左移是0010 逻辑右移是0100

B3层 发表时间: 06-12-21 11:00

回复: SysHu0teR [syshunter]   版主   登录
不赞同,先看左移,VC6下是这样
代码:

8:        unsigned char i=0x09;
0040B768  mov        byte ptr [ebp-4],9
9:        char j=0x09;
0040B76C  mov        byte ptr [ebp-8],9
10:      i<<=1;
0040B770  mov        al,byte ptr [ebp-4]
0040B773  shl        al,1
0040B775  mov        byte ptr [ebp-4],al
11:      j<<=1;
0040B778  mov        cl,byte ptr [ebp-8]
0040B77B  shl        cl,1
0040B77D  mov        byte ptr [ebp-8],cl


可以看到有符号的和无符号的都是shl,都做为逻辑左移,原因是shl和sal操作是一样的。

再看右移:
代码:

8:        unsigned char i=0x09;
0040B768  mov        byte ptr [ebp-4],9
9:        char j=0x09;
0040B76C  mov        byte ptr [ebp-8],9
10:      i>>=1;
0040B770  mov        al,byte ptr [ebp-4]
0040B773  shr        al,1
0040B775  mov        byte ptr [ebp-4],al
11:      j>>=1;
0040B778  mov        cl,byte ptr [ebp-8]
0040B77B  sar        cl,1
0040B77D  mov        byte ptr [ebp-8],cl


带符号j用的是sar,而无符号的i用的是shr,两个确实不同。


B4层 发表时间: 06-12-21 13:03

回复: kert_t8 [kert_t8]   论坛用户   登录
哦,对对,我分析运行结果的时候出错了

但是没道理啊,怎么会一个一样一个不一样呢??

B5层 发表时间: 06-12-22 14:05

回复: SysHu0teR [syshunter]   版主   登录
回忆一下补码。
下面全部是作为带符号数来说:

正整数的情况:最高位不能为1,00000001(+1)<<7 后变成了10000000,变成-128了
负整数的情况:最高位始终是1,11111111(-1)<<7 后变成了10000000(-128),再移的话就溢出了。

再举一个负整数的例子
10000001,再<<的话肯定溢出。

总结带符号数的左移,既正整数<<后如果最高位为1,或者负整数<<后最高位为0,统统算溢出。
所以不用考虑符号扩展的问题。


而>>则不同,负整数>>后为了保证还是负数高位始终得为1,反则正整数则为0。
11111111,不管怎么>>最后都是-1
00000001,不管怎么>>最后都是0

总的来说,这是由补码定义规定的。

个人感觉弄一个shl和sal,纯粹是为了与shr/sal配对好看。哈哈。



B6层 发表时间: 06-12-22 14:33

论坛: 编程破解

20CN网络安全小组版权所有
Copyright © 2000-2010 20CN Security Group. All Rights Reserved.
论坛程序编写:NetDemon

粤ICP备05087286号