只是昨晚我第一次遇到了好奇的Duff's device。我一直在做一些阅读,我不认为这是令人生畏的理解。我很好奇的是奇怪的语法(来自维基百科):
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 statement的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编写的,并且对于 count 和 n 变量具有隐式int。因为我标记了C ++,我修改了它。
修改2:修改了修订后的示例代码以说明无效的计数值。
答案 0 :(得分:8)
看看C ++ 11标准,我认为你要问的代码部分是允许的。你试过吗?
我认为最适用的规则是:
注意:通常,作为切换主题的子语句是复合的,
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);
答案 1 :(得分:1)
是的,这是合法的。 switch
语句的标签通常与switch
语句写在同一级别。但是,在复合语句中写入它们是合法的,例如在循环中间。
编辑:不要求switch语句的正文必须以标签开头,任何代码都是合法的。但是,从switch语句本身无法进入它,所以除非是循环或普通标签,否则代码将无法访问。
swtich
语句的另一个有趣之处是大括号是可选的。但是,在这种情况下,只允许使用一个标签:
switch (i)
case 5: printf("High five\n");
答案 2 :(得分: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
循环,但上面的代码似乎更自然地处理边界条件。