循环计数器&指针

时间:2011-06-13 21:39:51

标签: c performance pointers loops

我正在为图形编写一个专门的小型C99库,我经常得到这种形式的循环:

for(int i = 0; i < graph->nvertices; ++i) {
  // ...
}

我想知道这是不是一个好习惯,特别是在Tigh loop的情况下。起初我认为编译器足够聪明,只能看一次'graph-&gt; nvertices',而不是在每次迭代时查看它,但似乎不可能因为graph-&gt; nvertices可能在循环内部发生变化。写作更聪明,更快:

const int N = graph->nvertices;
for(int i = 0; i < N; ++i) {
  // ...
}

它似乎更快,因为它不需要多次查看指针,但它确实需要创建一个新变量。

注意:我想这是一种情况,能够阅读一些汇编代码以查看编译器实际正在做什么,如果有人有一个很好的参考我很乐意接受建议。

7 个答案:

答案 0 :(得分:3)

我倾向于自己做这些优化。有时编译器可以推断nvertices在整个循环中没有变化,但是如果你调用可能更改值的其他函数怎么办?编译器无法推断它,也可能无法优化代码。

此外,最好的方法是分析您的代码以查看两种方法之间的比较。

答案 1 :(得分:3)

尝试使用更高的优化设置,一些编译器应该能够为您优化。您也可以向后迭代,只用表达式初始化计数器:

for (int i = graph->nvertices; i >= 0; --i) 
  ..

然而,您将对缓存性能造成严重破坏。我认为你建议的方法是最直接的,这有助于编译器和下一个阅读代码的人清楚。

答案 2 :(得分:1)

我经常使用它。

const int N = graph->nvertices;
int i = 0;
for(; i < N; ++i) {
  // ...
}

答案 3 :(得分:1)

答案可能取决于您的编译器,但大多数编译器会为您生成可以学习的汇编列表。只需确保列出发布版本。

但是,如果我真的关心每一点性能,我可能会按照你的建议创建单独的计数变量。

最后,我怀疑它会产生明显的差异。

答案 4 :(得分:1)

您想方设法查看汇编程序代码。为此,您可以使用objdump程序,如下所示:

objdump -d executable

要过滤掉主要功能,请使用:

objdump -d executable | sed -n '/<main>/,/^$/p'

答案 5 :(得分:0)

这似乎是一个相当简单的测试方法,只需查看编译器的输出即可。整个程序优化通常会捕获这些低级优化。

另一方面,即使速度略有提高,我也不会进行这些类型的优化,因为我发现第一种形式更容易阅读和维护。

答案 6 :(得分:0)

我要去本地化变量的范围。然后,优化器将自行解决所有问题:

for(size_t i = 0, n = graph->nvertices; i < n; ++i) {
  // ...
}