让我们考虑C ++中的以下代码片段来打印第10个正整数:
for (int i = 1; i<11;i++)
{
cout<< i ;
}
这会比按顺序依次打印每个整数更快或更慢:
x =1;
cout<< x;
x++;
cout<< x;
等等..
有什么理由说它为什么要更快或更慢?它是否因语言而异?
答案 0 :(得分:3)
这个问题类似于this one;我复制了以下my answer to that question的摘录......(数字不同; 11对50;分析是相同的)
您正在考虑的是循环展开的手动形式。循环展开是编译器有时用于减少循环中涉及的开销的优化。只有在编译时可以知道循环的迭代次数(即迭代次数是常数,即使常量涉及基于其他常量的计算),编译器也可以这样做。在某些情况下,编译器可能会确定展开循环是值得的,但通常它不会完全展开它。例如,在您的示例中,编译器可以确定将循环从50次迭代展开到仅循环体的5个副本的10次迭代将是速度优势。循环变量仍然存在,但是现在代码只需要进行10次比较,而不是对循环计数器进行50次比较。这是一个权衡,因为循环体的5个副本在缓存中占用了5倍的空间,这意味着加载相同指令的额外副本迫使缓存逐出(抛出)已经存在的许多指令缓存以及您可能希望保留在缓存中的缓存。此外,从主内存加载循环体指令的4个额外副本所花费的时间远远长于在未完全展开循环的情况下从缓存中抓取已经加载的指令。
总而言之,仅使用循环体的一个副本并继续将循环逻辑留在原位通常更有利。 (即,根本不进行任何循环展开。)
答案 1 :(得分:1)
在循环中,实际的机器级指令将是相同的,因此是相同的地址。在显式语句中,指令将具有不同的地址。因此,对于for循环,CPU的指令缓存可能会提供性能提升,后者可能不会发生。
对于非常小的范围(10),差异很可能是微不足道的。对于相当长的循环,它可以更清楚地显示出来。