循环展开和 Duffs 设备
有时,直线环不能完全包含在环体内。这是因为,循环需要由某些语句 B 引发。然后,迭代从一些语句 A 开始,然后在循环之前再次跟随 B.
do_B();
while (condition) {
do_A();
do_B();
}
为了避免在代码中重复 B 两次出现潜在的剪切/粘贴问题,可以使用 Duff 的设备从 while
体的中间开始循环,使用 switch 语句并通过行为。
switch (true) while (condition) {
case false: do_A(); /* FALL THROUGH */
default: do_B(); /* FALL THROUGH */
}
Duff 的设备实际上是为了实现循环展开而发明的。想象一下将掩码应用于内存块,其中 n
是具有正值的带符号整数类型。
do {
*ptr++ ^= mask;
} while (--n > 0);
如果 n
总是被 4 整除,你可以轻松地将其展开为:
do {
*ptr++ ^= mask;
*ptr++ ^= mask;
*ptr++ ^= mask;
*ptr++ ^= mask;
} while ((n -= 4) > 0);
但是,使用 Duff 的设备,代码可以遵循这种展开的习惯用法,如果 n
不能被 4 整除,它就会跳到循环中间的正确位置。
switch (n % 4) do {
case 0: *ptr++ ^= mask; /* FALL THROUGH */
case 3: *ptr++ ^= mask; /* FALL THROUGH */
case 2: *ptr++ ^= mask; /* FALL THROUGH */
case 1: *ptr++ ^= mask; /* FALL THROUGH */
} while ((n -= 4) > 0);
现代编译器很少需要这种手动展开,因为编译器的优化引擎可以代表程序员展开循环。