这是一个有效的C代码吗?

时间:2010-08-02 05:31:52

标签: c++ c cpu-registers

  

可能重复:
  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代码?如果是这样,它想要实现什么,为什么有人会像上面这样做?

3 个答案:

答案 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的强制性链接。