可能重复:
What does the code do?
void duff(register char *to, register char *from, register int count)
{
register int n=(count+7)/8;
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);
}
}
以上是否有效的C代码?如果是这样,它想要实现什么,为什么有人会像上面这样做?
答案 0 :(得分:9)
它被称为 Duff的设备,您可以阅读它on wikipedia。
它解决了展开循环的一个问题:可能需要非整数次传递。一种方法是在主循环之外处理这个问题,但是使用Duff的设备更有效,它使用非常快速的跳转表并避免额外的循环开销来处理奇数个操作。
在您的示例中,这是一个内存副本,请与天真版本进行比较:
void memcpy(char* dst, char* src, size_t count)
{
begin:
if (count-- == 0) return;
*(dst++) = *(src++);
goto begin;
}
要复制15个字节,请执行以下操作:
测试计数, 复制, 环, 测试计数, 复制, 环, 测试计数, 复制, 环, 测试计数, 复制, 环, 测试计数, 复制, 环, 测试计数, 复制, 环, 测试计数, 复制, 环, 测试计数, 复制, 环, 测试计数, 复制, 环, 测试计数, 复制, 环, 测试计数, 复制, 环, 测试计数, 复制, 环, 测试计数, 复制, 环, 测试计数, 复制, 环, 测试计数, 复制, 环, 测试次数
注意必须完成“测试计数”和“循环”操作的次数。
使用您展示的duff版本,它更简单:
根据计数跳转, 复制, 复制, 复制, 复制, 复制, 复制, 复制, 测试计数, 环, 复制, 复制, 复制, 复制, 复制, 复制, 复制, 复制, 测试次数
节省了一半以上的步骤
答案 1 :(得分:5)
这是有效的。这是一个非常老派的循环展开。
基本上,不是检查被复制的每个字符的计数来确定何时停止,而只需要检查ceil(n / 8)次。
register关键字只是一个编译器提示,表明编译器试图将该值保存在寄存器中,而不是将其随机存入和移出主存储器。
显然这样的东西不再是必要的(memcpy()很可能在你编写的任何机器上实现非常快速的实现)但这样的技巧实际上提供了相当不错的性能胜利。
答案 2 :(得分:2)
Duff's Device on Wikipedia的强制性链接。