C 语言中的达夫设备 Duff’s Device

在495个必须知道的C语言问题这本书中,提到了一个达夫设备另类的算法设计技巧。如下:

 

[cpp] view plain copy
 
  1. register n = (count + 7) / 8; /* count > 0 assumed */  
  2. switch (count % 8)  
  3. {  
  4. case 0: do { *to = *from++;  
  5. case 7: *to = *from++;  
  6. case 6: *to = *from++;  
  7. case 5: *to = *from++;  
  8. case 4: *to = *from++;  
  9. case 3: *to = *from++;  
  10. case 2: *to = *from++;  
  11. case 1: *to = *from++;  
  12. while (--n > 0);  
  13. }  

 

 

书上的解释是: 这是个很棒的迂回循环展开法, 由Tom Duff 在Lucasfilm 时所设计。
它的“传统” 形态, 是用来复制多个字节。
这里count 个字节从from 指向的数组复制到to 指向的内存地址(这是个内存映射的输出寄存器, 这也是为什么它没有被增加)。
它把swtich 语句和复制8个字节的循环交织在一起, 从而解决了剩余字节的处理问题(当count 不是8 的倍数时)

简单的说,这个写法巧妙的完成了2个任务:

第一,我复制数据是按照一次8个字节来的,而不是复制一次比较一下索引,来判断当前是否超过了复制总长度。这样提高了效率,减小了判断次数。在非常大的数据复制中,我可以一次复制100个,判断10次就1000字节。

第二,那么数据不是8的倍数,或是设置数字的整数倍这么办。已经在这个case中解决了。就是利用case定位到while循环的剩余位置,完成余数的复制。

这是什么拐枣的语法 ? 能通过编译么? 能运行么?
事实上,经过我的测试是可以的。但这个排版不好,我需要重新排列一下。

[cpp] view plain copy
 
  1. register n = (count + 7) / 8; /* count > 0 assumed */  
  2. switch (count % 8) {  
  3.     case 0:   
  4.         do {   
  5.             *to = *from++;  
  6.    
  7.             case 7: *to = *from++;  
  8.             case 6: *to = *from++;  
  9.             case 5: *to = *from++;  
  10.             case 4: *to = *from++;  
  11.             case 3: *to = *from++;  
  12.             case 2: *to = *from++;  
  13.             case 1: *to = *from++;  
  14.         } while (--n > 0);  
  15. }  

 

可以这样理解:

第一,case 0 后面就一个循环语句。
第二,很多其他的case语句可以写在别的语句块中,仍然可以正确被case到。

那么这样,就产生了一个可能性。就是我可以根据switch的值,在选择while循环的开始执行位置。当然了,while可以换成for, 换成其他的语句块。

 

http://blog.csdn.net/tom_221x/article/details/38436127

posted @ 2017-05-11 11:30  sinferwu  阅读(155)  评论(0)    收藏  举报