Duff的设备在其他语言中是否适用?

9

许多年前,当Tom Duff在解决一个紧急的图形输入/输出问题时,他展开了一个循环,并创建了他的Duff's Device,如下所示:

dsend(to, from, count)
char *to, *from;
int count;
{
    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语言编码,并依赖于C语言中的case语句穿透。在其他编程语言中,这种交错控制结构的创造性是否可行呢?


什么是“旧式函数参数”? - Koray Tugay
5个回答

6

您可以在支持计算GOTO语句的任何语言中完成它(Fortran、某些BASIC等)。


但是,如果无法动态计算GOTO应跳转的地址,那么它会变得非常繁琐,以至于不再值得。因此,我认为在像PHP这样的动态语言中并不是一个好主意... - Janus Troelsen

5

它适用于C++。

但请注意,生成的代码取决于您的编译器。特别是,当我使用GCC针对ARM架构编译Duff设备时,无论优化级别如何,生成的ARM汇编程序都不够优化(我认为GCC将其转换为跳转表)。

最终,我只能手动编写汇编程序。


4
当编译器不会进行太多优化时(这正是Duff提出此方法的时期),它是有效的。问题在于每一步都有两种流程:落下和“case”标签,需要一个非常好的编译器才能理解它不需要刷新寄存器等操作。而且,一个这么好的编译器可能已经能够展开原始实现中的循环了。尽管如此,这仍然是一个不错的面试问题 :) - The Archetypal Paul

3

Duff的设备本质上是一种计算型的goto,在许多其他语言中也可以实现 - 汇编语言(当然)和FORTRAN是直接支持它们的几种语言。


3

我在JavaScript中非常成功地使用它来加速大数组处理。我希望我也能在C#中使用它。


2
可以。清理的情况不需要与循环相同。展开循环n/8次,然后在末尾执行7个条件步骤。考虑到它是用于大型数组的,最后7个步骤中的任何小的低效都会被忽略。 - The Archetypal Paul
3
保罗,如果清理代码不同于循环代码,那么我认为它就不能再被称为达夫设备了。达夫设备不仅仅是关于循环展开,而是使用“switch”语句跳转到循环展开的中间部分。 - Rob Kennedy

0
即使不能这样使用,您仍然可以有两个循环:
dsend(to, from, count)
char *to, *from;
int count;
{
    int n;
    for(n=0; n!=count/8; n+=8){
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
        *to = *from++;
    }
    for(; n!=count; n++)
    {
        *to = *from++;
    }
}

当然,使用较小的count会使速度稍慢,但它更易读,在不同编程语言中更易移植,并且在使用大型count时产生非常相似的效果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接