【问题标题】:Writing a macro for Duff's Device为 Duff 的设备编写宏
【发布时间】:2013-12-16 02:12:31
【问题描述】:

来自 Zed Shaw,Learn C the Hard Way,在练习 23 中,他谈到了 Duff 的设备。这是达夫的设备供参考:

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 的设备虽然在选择编码方面很漂亮,但并不是一个有用的通用 C 习语。您可能会在使用它时获得一些荣誉,但要为负面回击做好准备。
  • @chux- 我认为他只是想学习,这就是为什么要求它。
  • 我知道它对今天的处理器来说是普遍无用的,但是这个关于为它创建宏的问题真的让我很难过。我有兴趣弄清楚如何为它创建一个宏。如果不弄清楚,我今晚将无法入睡。
  • 哈,我也属于“如果你明确称它为'达夫的设备',那你就错了”的阵营。 ;)

标签: c c-preprocessor duffs-device


【解决方案1】:

类似这样的:

#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++

基本相同,只是不用八进制数。

【讨论】:

  • case ((x) * 8 + (y) + 1): 也可以正常工作,并且可以说更容易理解。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-05
  • 1970-01-01
  • 2016-08-29
  • 2011-01-27
  • 1970-01-01
相关资源
最近更新 更多