8

就在昨晚,我第一次遇到了好奇的达夫装置。我一直在阅读它,我认为理解它并不令人生畏。我很好奇的是奇怪的语法(来自维基百科):

register short *to, *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);
  }
}

我正在阅读switch 语句的 C++ 标准定义(如果它已经过时,请告诉我,我不熟悉 Open-Std.org)。据我所知,case 语句只是用于 switch 语句的简化跳转语句。

switch 本身完全忽略了嵌套的 do-while,循环忽略了 case 语句。由于开关在循环内部跳转,因此循环被执行。开关用于覆盖余数(除以 8),循环处理可整除的部分。这一切都说得通。

那么我的问题是为什么笨拙的语法?我突然想到,可以编写循环以使所有 case 语句都包含在其中,是吗?我在标准中看不到任何禁止这种行为的内容,并且它在 GCC 4.7 下可以正确编译,所以以下内容是否合法?

register short *to, *from;
register int count;
{
  register int n = (count + 7) / 8;
  switch (count <= 0 ? 8 : count % 8)
  {
    do
    {
      case 0:         *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++;
      default:        ; // invalid count, suppress warning, etc.
    } while(--n > 0);
  }
}

对我来说,这使代码的意图更加清晰。感谢您的任何反馈。;)

编辑:如下所述,原始代码是为 C 编写的,并且对countn变量具有隐式 int 。由于我将其标记为 C++,因此我对其进行了修改。

编辑 2:修改了修改后的示例代码以解决无效的计数值。

4

3 回答 3

8

查看 C++11 标准,我认为您要询问的代码部分是允许的。你试过了吗?

我认为最适用的规则是:

注意: 通常,作为 switch 主题的子语句是复合的,case并且default标签出现在(复合)子语句中包含的顶级语句上,但这不是必需的。

事实上,这意味着你可以去掉do-周围的大括号while,然后写

  int n = (count + 7) / 8;
  switch (count % 8) do
  {
      case 0:         *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++:

register n = (count + 7) / 8;

C++ 不允许 default-int,必须指定或推断变量的类型。


哦,在这里,在不破坏格式的情况下修复迭代次数:

  int n = 1 + count / 8;
  switch (count % 8) 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++;
      case 0:                      ;
  } while(--n > 0);
于 2013-01-14T22:11:24.573 回答
1

是的,这是合法的。语句的标签switch通常写在与语句相同的级别switch。但是,将它们写在复合语句中是合法的,例如在循环中间。

编辑:不要求 switch 语句的主体必须以标签开头,任何代码都是合法的。但是,从 switch 语句本身无法进入它,因此除非它是循环或普通标签,否则代码将无法访问。

该语句的另一个有趣之swtich处是大括号是可选的。但是,在这种情况下,只允许使用一个标签:

  switch (i)
      case 5: printf("High five\n");
于 2013-01-14T22:12:34.807 回答
1

该代码当然是合法的:对于块和/或循环完全没有要求。但值得注意的是,count == 0上述循环没有正确处理。但是,它可以通过以下方式正确处理:

int count = atoi(ac == 1? "1": av[1]);
switch (count % 4)
{
case 0: while (0 < count) { std::cout << "0\n";
case 3: std::cout << "3\n";
case 2: std::cout << "2\n";
case 1: std::cout << "1\n";
    count -= 4;
    }
}

case 0标签放在循环中也会错误地执行嵌套语句。虽然我看到 Duff 的设备总是使用do-while循环,但上面的代码似乎更自然地处理边界条件。

于 2013-01-14T22:30:27.610 回答