为Duff's Device编写宏。

4

在Zed Shaw的《学习C语言的艰苦方式》第23节中,他谈到了Duff's Device。以下是Duff's Device代码:

int duffs_device(char *from, char *to, 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);
        }
    }

    return count;
 }

他要求读者做如下事情:
创建一组宏,使您能够创建任意长度的设备。例如,如果您想要有32个 case 语句而不想编写所有内容,您能否创建一个宏,每次生成8个?
这真的让我困扰,我觉得我只需要正确的方向。非常感谢您的帮助!

Duff's Device虽然在某些编码方面很巧妙,但并不是一个有用的通用C语言习惯用法。你可能会因使用它而获得一些赞誉,但要准备好承受负面反弹。 - chux - Reinstate Monica
@chux- 我认为他只是想学习,这就是他为什么要问的原因。 - vidit
2
我知道在今天的处理器中它通常是无用的,但是关于为它创建一个宏的问题确实让我困扰。我有兴趣弄清楚如何为它创建一个宏。如果不解决这个问题,今晚我将无法入睡。 - Fumbster
哈哈,我也是“如果你明确地称之为‘达夫设备’的阵营,那么你就错了”的人。 ;) - Jim Buck
1个回答

6

类似这样的:

#define LAYDUFF(x, y) \
    case ((0 ## x ## y) + 1) : *to++ = *from++

#define SEVEN_AT_ONCE(x) \
    LAYDUFF(x,6); \
    LAYDUFF(x,5); \
    LAYDUFF(x,4); \
    LAYDUFF(x,3); \
    LAYDUFF(x,2); \
    LAYDUFF(x,1); \
    LAYDUFF(x,0)

#define EIGHT_AT_ONCE(x)    \
    LAYDUFF(x,7);           \
    SEVEN_AT_ONCE(x)

int duffs_device(char *from, char *to, int count)
{
    {
        int n = (count + 31) / 32;

        switch(count % 32) {
            case 0: do { *to++ = *from++;
                        SEVEN_AT_ONCE(3);                   
                        EIGHT_AT_ONCE(2);
                        EIGHT_AT_ONCE(1);
                        EIGHT_AT_ONCE(0);
                    } while(--n > 0);
        }
    }

    return count;
 }

将扩展为

        case ((036) + 1) : *to++ = *from++; // = 31

                     ...

        case ((000) + 1) : *to++ = *from++; // = 1

更新:

或者,您可以重写第一个宏:

        #define LAYDUFF(x, y) \
case (8 * x + y + 1) : *to++ = *from++

这基本上是一样的,只是它不使用八进制数。


1
case ((x) * 8 + (y) + 1): 可以正常工作,而且可能更容易理解。 - rici

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