我最近遇到过编写以下代码的情况:
for(int i = 0; i < (size - 1); i++)
{
// do whatever
}
// Assume 'size' will be constant during the duration of the for loop
在查看此代码时,它让我想知道为每个循环如何评估for循环条件。具体来说,我很好奇编译器是否会优化掉&#39;必须为每个循环执行的任何其他算术。在我的情况下,这个代码是否会被编译为每次循环迭代都必须评估(size-1)?或者编译器是否足够聪明才能意识到&#39; size&#39;变量不会发生变化,因此它可以为每次循环迭代预先计算它。
这让我想到了一个条件语句的一般情况,这个条件语句可能指定了多于必要的操作。
作为一个例子,下面两段代码将如何编译:
if(6)
if(1+1+1+1+1+1)
int foo = 1;
if(foo + foo + foo + foo + foo + foo)
编译器有多聪明?上面列出的3种情况是否会被转换为相同的机器代码?
虽然我在,为什么不列出另一个例子。如果您在一个不会对最终结果产生任何影响的条件中进行操作,编译器会做什么?例如:
if(2*(val))
// Assume val is an int that can take on any value
在这个例子中,乘法是完全没必要的。虽然这个案例看起来比我原来的情况要糟糕得多,但问题仍然存在:编译器是否能够删除这种不必要的乘法?
问题:
答案 0 :(得分:4)
简短回答:编译器异常聪明,并且通常会优化您提出的那些案例(包括完全忽略不相关的条件)。
语言新手在真正理解C ++方面面临的最大障碍之一是,他们的代码与计算机执行的内容之间没有一对一的关系。该语言的全部目的是创建一个抽象。您正在定义程序的语义,但计算机没有责任逐行实际遵循您的C ++代码;事实上,如果它这样做,与现代计算机的速度相比,它会非常缓慢。
一般来说,除非你有理由进行微观优化(游戏开发人员会想到),否则最好几乎完全忽略这个编程方面,并相信你的编译器。在执行所需的计算之后,编写一个获取所需输入并提供所需输出的程序...并让编译器尽一切努力弄清楚物理机器将如何实现所有这些。
有例外吗?当然。有时您的要求是如此具体,以至于您比编译器更了解,并最终优化。您通常在分析并确定您的瓶颈之后执行此操作。并且也没有理由写故意愚蠢的代码。毕竟,如果你不想让你的程序复制一个50MB的矢量,那么它将复制一个50MB的矢量。
但是,假设合理的代码意味着它的样子,你真的不应该花太多时间来担心这个问题。因为现代编译器在优化时非常好,所以你试图跟上它是个傻瓜。
答案 1 :(得分:2)
检查 https://meta.stackexchange.com/questions/25840/can-we-stop-recommending-the-dragon-book-please 对于一些书籍推荐,如果你真的想了解编译器可能会做什么。这是一个非常复杂的主题。
您还可以使用-S
选项(gcc / g ++)编译到程序集,以查看编译器实际执行的操作。使用-O3
/ ... / -O0
/ -O
来尝试不同的优化级别。
答案 2 :(得分:2)
C ++语言规范允许编译器进行任何优化,导致对预期结果没有可观察到的更改。
如果编译器可以确定size
是常量且在执行期间不会改变,那么它肯定可以进行特定的优化。
或者,如果编译器也可以确定循环中没有使用i
(并且之后没有使用它的值),那么它只用作计数器,它可能很好地将循环重写为:
for(int i = 1; i < size; i++)
因为这可能会产生更小的代码。即使以某种方式使用此i
,编译器仍然可以进行此更改,然后调整i
的所有其他用法,以便可观察的结果仍然相同。
总结:一切顺利。只要可观察结果相同,编译器可能会也可能不会进行任何优化更改。