打印

关于C语言中的移位运算的一个疑问,望各位大侠帮忙解答

[复制链接]
2356|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
LEON1741|  楼主 | 2008-5-19 20:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
大家都知道,实现高效的C 语言编写的方法中,有一招是使用位操作。
我前几天在网上看到一篇**中讲到以下一个例子,就是关于移位运算的问题。
作者给了一个比较,首先是正常的运算:
int I,J;
I=257/8;
J=456%32;

然后是位运算:

int I,J;
I=257>>3;
J=456-(456>>4<<4);

并说第二种方法仅仅是几句相关的汇编,代码更简洁、效率更高。
这是没错,
但是其中的J的运算表达式中,为什么要先右移4位后再左移4位?
它原来是除32求余,换算过来应该也是5位啊?那它移4位的结果应该会出错吧

于是我自己去Turbo C环境下试了试,
却发现不仅仅4行,6也行,运算结果都和5一样,只是3和7不一样
具体程序如下:

main()
{
    int k,l,m,n,o;

    k  = 456 - (456>>3<<3);
    l   = 456 - (456>>4<<4);
    m = 456 - (456>>5<<5);
    n  = 456 - (456>>6<<6);
    o  = 456 - (456>>7<<7);

    printf("%d,%d,%d,%d,%d",k,l,m,n,o);
}

其输出结果依次是:0,8,8,8,72

因此想在这求助各位大侠们,帮我解释一下为什么……
多谢啦~~

相关帖子

沙发
computer00| | 2008-5-19 20:35 | 只看该作者

晕...是他把问题搞复杂化了……

J=456 & (0x1F);  //直接把高位搞成0即可,剩下的5位就是余数。

另外,像这样的操作,很多编译器会直接生成移位或者是位操作的指令。
例如keil下:

  1445:  unsigned char i,j; 
  1446:  i=255; 
C:0x0987    7FFF     MOV      R7,#0xFF  ;对应的i=255;
  1447:  i=i/8; 
C:0x0989    EF       MOV      A,R7 ;生成了循环右移指令
C:0x098A    13       RRC      A
C:0x098B    13       RRC      A
C:0x098C    13       RRC      A
C:0x098D    541F     ANL      A,#0x1F
C:0x098F    FF       MOV      R7,A
  1448:  i=i%32;  ;直接生成与指令
C:0x0990    53071F   ANL      0x07,#0x1F

使用特权

评论回复
板凳
quan8310| | 2008-5-19 22:02 | 只看该作者

合理的解释应该是--巧合

456化为二进制数为111001000,你要对32求余,实质就是2楼说的后5位。
所以你
 l   = 456 - (456>>4<<4);
    m = 456 - (456>>5<<5);
    n  = 456 - (456>>6<<6);
这三个操作都刚好结果一样。

使用特权

评论回复
地板
寒雨飞扬| | 2008-5-23 15:45 | 只看该作者

3楼对了

我也刚注意了一下456对应的二进制数据,确实是因为巧合。
J=456 & (0x1F);  
不过二楼说的方法才是最快的。

使用特权

评论回复
5
djyos| | 2008-5-24 15:55 | 只看该作者

貌似不用那么麻烦了

现在编译器都帮你把这活干了,乘法或除法的两个操作数,如果有一个是2的n次方的常数,大多数编译器都会用移位代替乘除,省却很多麻烦,比如gcc就是这样干活的。

使用特权

评论回复
6
leon1741| | 2008-5-26 20:29 | 只看该作者

多谢大家啦

感谢大家的帮忙指点,特别是二楼的兄台
问题已经懂了,非常感谢!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

3

帖子

0

粉丝