概述
上个世纪80年代突然出现下面这么一段程序
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);
}
这是一段吓死人的程序,特别是某些大公司里面的经过编程规范“特训”过的战士。这就是传说中的达夫设备(duff's device)。你能想象和敢想象switch还能这么用吗?当时
Tom Duff这么用是为了增加内存复制的效率。因为正常情况下内存复制应该是这样的:
for(i=0; i<n; i++)
*to++ = *from++;
但是这样复制的话,每次执行一行就会判断一次,影响效率。而达夫设备可以执行8次才需要判断一次,这样就可以明显提高效率。但是,如果你真想提高效率的话,如果给你老板看到的话,估计你就要被炒掉了。但是这样可以给我们下面两个启示。
启示1★新的复制方法
这点启示主要来自于达夫设备的复制方法,他的目的只是想每次循环多执行几次复制,那么为了我们的编码规范,我们可以采用下面的方法:
times = n / 8;
for(i=0; i<n%8; i++)
*dest++ = *src++;
for(i=0; i<times; i++)
{
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
*dest++ = *src++;
}
启示2★在switch里面随意增加控制语句
对于达夫设备,之所以难以接受这样的代码,是因为以前没有人告诉我们case语句之间可以随意添加控制语句。比如下面的语句:
#include <stdio.h>
int main()
{
int i;
for(i=0; i<10; i++)
{
switch(i)
{
default:if(i%2)
break;
case 100:
printf("%d\t", i);
}
}
}
结果会输出:0
2
4
6
8
小结
首先,这里介绍达夫设备并不意味着我推荐使用它。他就像goto语句一样,现在沟通语句基本已经绝迹了吧!我们的C语言一般都会说goto语句会带来多少多少灾难性的后果,推荐我们不到必要的时候不要使用它。一般我们看到上面那句话估计以后就不会再使用goto语句了。因为我们都怕麻烦。
但是呢,我们看linux内核,tcp/ip协议栈,随处可见的goto语句,你看我们的linux内核,网络不是运行得很好嘛。而这个达夫设备呢,它比goto语句复杂,但是确可以在很多编译器通过,至少VC和gcc可以过。有句很经典的话,“存在即合理”。既然goto语句和switch语句嵌套控制语句是可行的,了解了解也是可以的。方便的时候,用用也是不错的。(如果说推荐估计给人喷死了!%>_<%~~~)
再再但是呢,有两位大神还真用达夫设备解决了两个大问题。其中有一个还用得不亦乐乎(O(∩_∩)O哈哈~)。
预知后事如何,请看这篇博文: