循环展开和 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);

现代编译器很少需要这种手动展开,因为编译器的优化引擎可以代表程序员展开循环。