【问题标题】:loop condition evaluation循环条件评估
【发布时间】:2010-11-17 13:12:31
【问题描述】:

只是一个简单的问题。

我有一个看起来像这样的循环:

for (int i = 0; i < dim * dim; i++)

for 循环中的条件是否在每个循环中都重新评估?

如果是这样,做这样的事情会更有效率吗?:

int dimSquare = dim * dim;
for (int i = 0; i < dimSquare; i++)

谢谢

-伪造

【问题讨论】:

    标签: c++ optimization for-loop


    【解决方案1】:

    编译器会在循环开始前预先计算 Dim * Dim 的值

    【讨论】:

    • 除非 Dim 可以在循环内修改。
    • 那么你的意思是在for循环中,即使dim的值在循环期间发生变化,循环也会一直运行直到达到预编译值?或者当 dim 在循环中途发生变化时,程序会重新评估它吗?
    • @Faken,如果有任何 Dim 变化的可能性,编译器将重新评估它每个循环。
    • 但是在这个例子中,当问题被问到时,它不能。所以它只会在循环之前预先计算一次。
    【解决方案2】:

    是的,从语义上讲,它将在每个循环上进行评估。在某些情况中,编译器可能能够自动从循环中删除条件 - 但并非总是如此。特别是:

    void foo(const struct rect *r) {
      for (int i = 0; i < r->width * r->height; i++) {
        quux();
      }
    }
    

    在这种情况下,编译器将无法将乘法移出,因为它所知道的quux() 修改了r

    一般来说,通常只有局部变量才有资格将表达式从循环中提升出来(假设您从不获取它们的地址!)。虽然在某些情况下结构成员也可能符合条件,但有很多事情可能导致编译器假设内存中的所有内容都已更改——例如,写入几乎任何指针,或调用几乎任何函数。因此,如果您在那里使用任何非本地变量,最好假设不会发生优化。

    也就是说,一般来说,我只建议主动将可能昂贵的代码移出条件:

    • 这样做不会影响可读性
    • 显然会花费非常很长时间(例如,网络访问)
    • 或在分析时显示为热点。

    【讨论】:

    • 请注意,在您的示例中 r 可能是 const struct rect*,并且不允许编译器 still 假定 quux() 不会以某种方式修改其数据成员通过别名。通常认为 const 会激活各种编译器优化方式,但它并不像人们最初想象的那么简单。
    • @onebyone:确实。不过,Restrict 在这里可能会有所帮助。
    • 是的,对于 C++ 编译器,它们也是 C99 编译器,因此支持限制。严格的别名规则有助于“写入几乎任何指针”,但不适用于“调用几乎任何函数”。内联应该有助于函数。
    • 是的。 'r' 很可能指向一个全局变量。或者全局变量指向的东西。等等。
    • 或具有非全局名称的“全局”,例如静态类成员。甚至是函数静态变量。
    【解决方案3】:

    一般来说,例如,如果您要在循环中更改“dim”的值,则每次都会重新评估它。但由于在您的示例中并非如此,因此一个体面的编译器会优化您的代码,并且您不会看到任何性能差异。

    【讨论】:

    • 很抱歉这个答案经过深思熟虑的人,但这个答案以清晰简洁的方式向我解释了一切。
    • 但是不要忘记记住 bdonlan 关于使用局部变量进行循环控制的建议——局部变量使编译器更容易优化,因为它们的可见性是有限的(这也有助于读者理解,而不是只是编译器优化)。
    • 如果我是你,我不会道歉。这让 bdonlan 在“民粹主义”徽章上获得了不错的机会,还有 9 票(在撰写本文时),如果 Lulu 再获得 8 票 :-)
    • @onebyone,好吧,如果你这么说,我想我也得给这个投票;)
    • decenet 编译器也有望将你的 i++ 变成 ++i :-)
    猜你喜欢
    • 1970-01-01
    • 2011-12-17
    • 2010-10-02
    • 1970-01-01
    • 2018-06-23
    • 1970-01-01
    • 1970-01-01
    • 2014-06-03
    • 1970-01-01
    相关资源
    最近更新 更多