switch 语句 - 修改 Duff 设备的语法 - 这是合法的 C/C++吗?

switch statement - Revising the syntax of Duff's device - Is this legal C/C++?

本文关键字:C++ 语法 修改 语句 Duff switch      更新时间:2023-10-16

就在昨天晚上,我第一次遇到了好奇的达夫的设备。我读了一些这方面的资料,我觉得理解起来并不难。我好奇的是奇怪的语法(来自维基百科):

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语句。由于switch跳转到循环内部,因此循环被执行。开关的作用是覆盖剩余部分(被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);
  }
}

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

Edit:如下所述,原始代码是为C编写的,并且对于countn变量具有隐式int。因为我把它标记为c++,所以我修改了它。

Edit 2:修改了修改后的示例代码,以考虑无效的计数值。

看看c++ 11标准,我想你问的那部分代码是允许的。你试过吗?

我认为最适用的规则是:

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

实际上,这意味着您可以去掉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);

代码当然是合法的:完全没有关于块和/或循环的要求。值得注意的是,上面的循环不能正确处理count == 0。但是,下面这个代码可以很好地处理它:

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

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

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

EDIT:没有要求switch语句体必须以标签开头,任何代码都是合法的。然而,没有办法从switch语句本身进入它,所以除非它是一个循环,或者一个普通的标签,否则代码将是不可访问的。

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

  switch (i)
      case 5: printf("High fiven");