Content #
send(to, from, count)
register short *to, *from;
register count;
{
register 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 语句和 while 语句整合在了一起,形成了令人疑惑的 switch 和 while 交错在一起的代码,但是代码量减少了将近一半。正常情况下我们会将 case 语句的作用域视作一个单独的代码块(block),而达夫设备表明实际上并不是这样。所以为什么可以这样写呢?
我们可以查阅最新的 C17 草案 PDF 版本,直接跳转到在 6.8 Statements and blocks,可以看到 case 语句属于 Labeled statements(带标签的语句:
labeled-statement:
identifier : statement
case constant-expression : statement
default : statement
并且任何一条语句都能在自己前面声明一个标识符作为标签名称,标签本身并不会改变控制流,控制流在它们之间执行不受阻碍: Any statement may be preceded by a prefix that declares an identifier as a label name. Labels in themselves do not alter the flow of control, which continues unimpeded across them.
达夫设备的巧妙之处在于,它巧妙地利用了 Labeled statements 不改变控制流的语法定义;而正常情况下我们会将 case 语句的作用域视作一个单独的代码块,仅仅是 code style 的最佳实践而已,并不是编译器强约束的。
当达夫设备开始运行时,会先根据 switch 匹配到对应的 case 语句,由于没有声明 break 所以会一路向下执行(falls through)直到被 while 捕获,进入循环逻辑。
From #
https://zhuanlan.zhihu.com/p/284223705