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

来源:互联网 发布:unity3d圣典中文手册 编辑:程序博客网 时间:2024/05/20 06:26

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

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循环的剩余位置,完成余数的复制。

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

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, 换成其他的语句块。

最后,我深深的觉得这个写法碉堡了,但是可能会依赖编译的语法分析实现细节。有机会我要试试 !




1 0
原创粉丝点击