void Send(int * to, const int* from, const int count)
{
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);
}
}
Run Code Online (Sandbox Code Playgroud)
Pet*_*ham 17
这是Duff的设备.这是一种展开循环的方法,避免了必须添加辅助修复循环来处理循环迭代次数不知道是展开因子的精确倍数的时间.
由于这里的大多数答案似乎总体上是积极的,我会反对它.
使用此代码,编译器将很难将任何优化应用于循环体.如果您只是将代码编写为一个简单的循环,那么现代编译器应该能够为您处理展开.这样,您可以保持可读性和性能,并希望将其他优化应用于循环体.
其他人引用的维基百科文章甚至说,当这个"模式"从Xfree86源代码中删除时,性能实际上得到了提升.
这种结果通常是盲目地优化您认为可能需要它的任何代码.它可以防止编译器正常工作,使代码可读性降低,更容易出错并且通常会降低编码速度.如果你在第一时间以正确的方式做事,即编写简单的代码,然后分析瓶颈,然后进行优化,你甚至不会想到使用这样的东西.无论如何,不是使用现代CPU和编译器.
理解它很好,但如果你真的使用它我会感到惊讶.
这种交换语句和while循环的混合被称为"Duff的设备".这是一种展开循环的方法,这是以前经常使用的优化.
因此,此代码仍然将内存内容从一个位置复制到另一个位置,但它可能更有效.请注意,在今天的架构上,你应该总是测量它,因为有了缓存局部性和快速的CPU循环展开通常是一个坏主意.
这在功能上与下面的代码相同:
for(int i=0;i<n;i++)
{
*to++=*from++;
}
Run Code Online (Sandbox Code Playgroud)
不同之处在于您的代码展开循环,因此复制的每8个整数只需要1次循环迭代.由于任何情况都没有中断,因此从每个案例标签到下一个案例标签都会执行.
当count%8 == 0时,在第一次迭代的循环内执行8个副本
当count%8 == 7时,第一次迭代执行7个副本
等等.在使用%8副本进行第一次迭代后,每次迭代恰好会发生8个副本.
通过以这种方式展开循环,循环开销显着降低.重要的是要注意案例值(0,7,6,5,4,3,2,1)的顺序,它们有助于编译器将其转换为跳转表.
更新
OP发布的示例代码的问题是计数值为0将导致发生8个副本,可能导致缓冲区溢出.