您的位置:首页 > 其它

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

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

[cpp] view
plaincopy

register n = (count + 7) / 8; /* count > 0 assumed */

switch (count % 8)

{

case 0: do { *to = *from++;

case 7: *to = *from++;

case 6: *to = *from++;

case 5: *to = *from++;

case 4: *to = *from++;

case 3: *to = *from++;

case 2: *to = *from++;

case 1: *to = *from++;

} while (--n > 0);

}

书上的解释是: 这是个很棒的迂回循环展开法, 由Tom Duff 在Lucasfilm 时所设计。

它的“传统” 形态, 是用来复制多个字节。

这里count 个字节从from 指向的数组复制到to 指向的内存地址(这是个内存映射的输出寄存器, 这也是为什么它没有被增加)。

它把swtich 语句和复制8个字节的循环交织在一起, 从而解决了剩余字节的处理问题(当count 不是8 的倍数时)

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

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

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

这是什么拐枣的语法 ? 能通过编译么? 能运行么?

事实上,经过我的测试是可以的。但这个排版不好,我需要重新排列一下。

[cpp] view
plaincopy

register n = (count + 7) / 8; /* count > 0 assumed */

switch (count % 8) {

case 0:

do {

*to = *from++;

case 7: *to = *from++;

case 6: *to = *from++;

case 5: *to = *from++;

case 4: *to = *from++;

case 3: *to = *from++;

case 2: *to = *from++;

case 1: *to = *from++;

} while (--n > 0);

}

可以这样理解:

第一,case 0 后面就一个循环语句。

第二,很多其他的case语句可以写在别的语句块中,仍然可以正确被case到。

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

最后,我深深的觉得这个写法碉堡了,但是可能会依赖编译的语法分析实现细节。有机会我要试试 !
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: