我在VC ++中有以下代码:
for (int i = (a - 1) * b; i < a * b && i < someObject->someFunction(); i++)
{
// ...
}
据我所知编译器优化所有这些算术运算并且它们不会在每个循环上执行,但我不确定它们是否可以告诉上面的函数每次都返回相同的值并且它不会每次都需要调用。
将所有计算保存到变量中,或仅依靠编译器优化来获得更易读的代码,是否更好?
int start = (a - 1) * b;
int expra = a * b;
int exprb = someObject->someFunction();
for (int i = startl i < expra && i < exprb; i++)
{
// ...
}
答案 0 :(得分:7)
简短回答:这取决于。如果编译器可以每次推断出运行someObject->someFunction()
并且一旦两者产生相同的效果就缓存结果,则允许(但不保证)这样做。这种静态分析是否可行取决于您的程序:具体来说,someObject
的静态类型是什么,它的动态类型是什么,以及someFunction()
实际上做了什么,是否virtual
int start = (a - 1) * b;
int expra = a * b;
int exprb = someObject->someFunction();
for (int i = start; i < expra && i < exprb; i++)
// ...
1}},等等。
一般情况下,如果只需要完成一次,那么编写代码的方式只需要可以只执行一次,而无需担心编译器可能会发生什么正在做:
for (int i = (a - 1) * b, expra = a * b, exprb = someObject->someFunction();
i < expra && i < exprb; i++)
// ...
或者,如果你简明扼要:
{{1}}
答案 1 :(得分:6)
根据我的经验,VC ++编译器不会优化函数调用,除非它可以在编译调用代码时看到函数实现。因此,将呼叫移出循环是个好主意。
答案 2 :(得分:5)
如果函数与调用者位于同一个编译单元中,编译器通常可以推导出关于它的一些事实 - 例如它的输出可能不会为后续调用而改变。但总的来说,情况并非如此。
在您的示例中,为这些简单的算术表达式分配变量并不会真正改变与生成的对象代码有关的任何内容,并且在我看来,这使得代码的可读性降低。除非你有一堆长表达式无法合理地放在一行或两行中,否则你应该避免使用临时变量 - 如果没有其他原因,那么只是为了减少命名空间污染。
使用临时变量意味着程序员的管理开销很大,以便将它们分开并避免意外的副作用。它还使得重复使用代码片段变得更加困难。
另一方面,将函数的结果赋给变量可以通过显式避免多个函数调用来帮助编译器更好地优化代码。
就个人而言,我会这样做:
int expr = someObject->someFunction();
for (int i = (a - 1) * b; i < a * b && i < expr; i++)
{
// ...
}
答案 3 :(得分:1)
编译器不能假设您的函数每次都返回相同的值。让我们假设您的对象是一个套接字,编译器怎么可能知道它的输出是什么?
此外,编译器在此类循环中可以进行的优化很大程度上取决于a和b是否声明为const
,以及它们是否是本地的。使用高级优化方案,它可能能够推断a和b既未在循环中也未在函数中被修改(再次,您可能会想象您的对象对它们有一些引用)。
嗯,简而言之:转到代码的第二个版本!
答案 4 :(得分:0)
编译器很可能每次调用该函数。
如果您关心代码的可读性,那么使用:
int maxindex = min (expra, exprb);
for (i=start; i<maxindex; i++)
恕我直言,长线不会提高可读性。
编写短线并执行多步以获得结果,不会影响性能,这正是我们使用编译器的原因。
答案 5 :(得分:0)
有效的是你可能会问的是编译器是否会内联函数someFunction()以及它是否会在每个循环中看到someObject是同一个实例,如果它同时执行它们,它将潜在地“缓存”返回值和不要继续重新评估它。
这很大程度上取决于你使用VC ++以及任何其他编译器的优化设置,尽管我不确定VC ++会给你提供与gnu一样多的标志。
我经常发现程序员依靠编译器优化他们可以轻松优化的东西是令人难以置信的。只要将表达式移动到for循环的第一部分,如果你知道它每次都会计算相同的结果:
只需这样做,不要依赖编译器:
for (int i = (a - 1) * b, iMax = someObject->someFunction();
i < a * b && i < iMax; ++i)
{
// body
}