循环内是否有常量函数返回值的优化?

时间:2015-08-04 21:07:46

标签: c++ gcc optimization

我的问题是关于gcc编译器。

通常,在循环中,我必须使用在整个循环期间保持不变的函数返回的值。

我想知道在变量中预先存储这个常量返回值是否更好(让我们设想一个长循环),或者像gcc之类的编译器是否能够执行一些优化来缓存常量值,因为它会认为它不断地抛出循环。

例如,当我在字符串中循环字符时,我经常写这样的东西:

bool find_something(string s, char something)
{
    size_t sz = s.size();
    for (size_t i = 0; i != sz; i++)
        if (s[i] == something) return true;
    return false;
}

但是使用一个聪明的编译器,我可以使用以下(更短更清晰):

bool find_something(string s, char something)
{
    for (size_t i = 0; i != s.size(); i++)
        if (s[i] == something) return true;
    return false;
}

然后编译器可以检测到循环内的代码没有对string对象执行任何更改,然后构建一个代码来缓存s.size()返回的值,而不是为每次迭代进行(较慢)函数调用。

gcc是否有这样的优化?

3 个答案:

答案 0 :(得分:2)

通常,您的示例中没有任何内容使编译器无法在循环之前移动android:padding="-20dp"计算。实际上,GCC 5.2.0将为您展示的两种实现生成exactly the same code

我强烈建议反对依赖于这样的优化(在真正的性能关键代码中)因为某处的小改动(GCC优化器,.size()的实现细节,... )可能会破坏GCC进行优化的能力。

但是,我认为在通常的90%代码中编写更详细的版本并不是真正具有性能关键性。

鉴于目前的C ++编译器,我会更加简洁:

std::string

哪个BTW也会产生与GCC 5.2.0非常相似的机器代码。

答案 1 :(得分:1)

编译器必须知道对象未在不同的线程中修改。如果对象没有改变,它可以告诉函数不会改变,但是它不能告诉对象不会从其他刺激中改变。

如果您包含某种形式的整体程序优化,编译器将展开对具有大小的成员的调用

答案 2 :(得分:0)

这取决于编译器是否可以将函数调用识别为常量。请考虑以下可能驻留在外部库中的函数,该函数无法由编译器进行分析。

var spinner = $('<i class="fa fa-refresh fa-spin"></i>');
var button = $("#CMSub");
button.css({'width':button[0].clientWidth + 'px'});
function refreshreplace() {
  button.text('');
  button.append(spinner);
}

无论输入参数如何,此函数都将返回不同的值。因此,即使传递的字符串对象保持不变,编译器也不能假定常量返回值。不会进行任何优化。

另一方面,如果编译器检测到常量函数调用(在您的示例中可能就是这种情况),则可能会将常量表达式移出循环。

较早版本的int odd_size(string s) { static int a = 0; return a++; } 有一个明确的选项gcc,负责该任务。来自gcc-3.4.5 documentation

  

-floop-优化

     

执行循环优化:将常量表达式移出循环,简化退出测试条件,并可选择执行强度降低和循环展开。

     

在-O,-O2,-O3,-Os等级启用。

我在-floop-optimize的当前版本中找不到此选项,但我确信它们也包含此类优化。