博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
什么是达夫设备(Duff's Device)
阅读量:2260 次
发布时间:2019-05-09

本文共 2012 字,大约阅读时间需要 6 分钟。

在看《你必须知道的496个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 的倍数时)。相信不相信, 象这样的把 case 标志放在嵌套在 swtich 语句内的模块中是合法的。当他公布这个技巧给 C 的开发者和世界时, Duff 注意到 C 的 swtich 语法, 特别是 跌落" 行为, 一直是被争议的, 而这段代码在争论中形成了某种论据, 但我不清楚是赞成还是反对”

函数包含一个switch语句,它的case语句同时位于一个while循环体内(有一个case语句在外面)。switch内的表达式计算被八除的余数。执行开始于while循环内的哪个位置由这个余数决定,最终循环退出,(没有break)。Duff’s Device这样就简单漂亮地解决了边界条件的问题。顺便提一下,为什么”case 0”标记在循环外面呢?这样不是打破了对称的美观吗?这样做的唯一理由是为了处理空序列。当余数为零,”case 0”内就需要执行一个多余的测试来判断空序列的可能性。总之,这是个很酷的算法。

达夫设备是一个加速循环语句的C编码技巧。其基本思想是–减少循环测试的执行次数。

如果在一个for循环中,其中操作执行得如果足够快(比如说,一个赋值)——那么测试循环条件占用了循环所用时间的很大部分。循环应该被部分解开,这样数个操作一次完成,测试操作也做的较少。其实,是通过switch语句将要进行的连续循环操作的次数进行了预判(根据擦case语句的位置)然后依次执行,而不必每次都去进行测试条件。

在这里Duff’s Device是个新颖的,有创造力的解决方案。这里有一个使用该模型的一个实例:快速拷贝和填充。

Duff’s Device对效率的负面影响可能来自于代码膨胀(一些处理器更善于处理紧凑的循环而不是大的循环)和特别的结构。优化器被做成当遇一些更加技巧性的结构时可能会不知所措从而生成比较保守的代码。

其实达夫设备是使用switch语句来控制进入循环的位置。

下面的程序是简单验证达夫设备的执行:

#include 
#include
int main(int argc, char* argv[]){ int n; if(argc < 2) { printf("Two arguments at least!\r\n"); return -1; } n = atoi(argv[1]); switch(n) { do { case 0: printf("%d ",0); case 1: printf("%d ",1); case 2: printf("%d ",2); case 3: printf("%d ",3); case 4: printf("%d ",4); }while(--n>0); } return 0;}

运行结果演示:

这里写图片描述

原文出处:

你可能感兴趣的文章
Linux 压缩命令 (gzip / bzip2 / zip / tar) 特点及区别
查看>>
linux 面试题 及 参考答案
查看>>
Java集合框架学习总结
查看>>
Java 并发指南开篇:Java 并发编程学习大纲
查看>>
JVM 原理学习总结
查看>>
搞定计算机网络面试
查看>>
再谈GC1:GC简介,分代与回收算法
查看>>
高并发与多线程的关系与区别
查看>>
秋招复习之系统设计
查看>>
mac jdk1.8 mysql5.7 环境配置
查看>>
shell terminal bash zsh 区别 / 关系
查看>>
从输入URL到页面可交互的过程探究之一:从服务端到客户端
查看>>
前端应该如何准备数据结构和算法?
查看>>
程序猿与杰伦的“第一次”
查看>>
一文看懂《子数组的最大乘积问题》
查看>>
不借助变量交换两个数
查看>>
【LeetCode】342. 4的幂
查看>>
100 * 100 Canvas 占用内存多大
查看>>
数据结构知否知否系列之 — 队列篇
查看>>
递归和动态规划
查看>>