用指针替换循环索引器有什么好处吗?

时间:2015-01-22 20:16:51

标签: c++ visual-c++ optimization micro-optimization

假设:

const int n = bigNumber;
float* f = someData;

转换中有什么意义吗

for (int i = 0; i < n; i++)
{
    f[i] += 1;
}

float* lastF = f + n;
for (float* i = f; i < lastF; i++)
{
    *i += 1;
}

天真地看着这个,似乎我为每次迭代(f[i])保存了一个加法运算。

当然,这假设我对循环内的索引器的值没有兴趣。

  1. 我对这种心态是否正确?
  2. 如果是这样,我的编译器是否足够聪明,可以单独执行此操作(假设启用了所有优化标志)?
  3. 我会检查拆卸,但我读这些很糟糕。

3 个答案:

答案 0 :(得分:5)

没有任何好处。如今,任何编译器都可以比大多数程序员更好,更快地完成它。

如果代码中f[i++]的可读性高于*fp++,请不要再三考虑。它们将被编译为完全相同的目标代码。

答案 1 :(得分:3)

像MS Visual Studio这样的现代编译器非常聪明,可以在内部将索引表单转换为指针表单。

但是,看到您正在使用MS Visual Studio,您最好坚持索引表单,因为它更适合MS Visual Studio的vectorizing optimizer

索引表单是推荐的表单,Visual Studio更容易理解。指针形式更难以让编译器理解;如果编译器感到困惑,你可能无法理解为什么。

例如,在我的Visual Studio编译器(版本2013)中,索引表单被编译为AVX代码(256位寄存器,如ymm0),而指针表单使用SSE(128位寄存器,如{{ 1}}) - 可能慢了2倍(没有测量它)。

答案 2 :(得分:1)

差异太大了,没有一般规则。

这两段代码在逻辑上是等价的,所以在as-if下如果编译器可以自由地将一个代码视为另一个代码。

如果采用i的值或地址,情况会发生变化,特别是如果它是“非本地”传递的,因为这会强制编译器放弃将一个变换为另一个的能力。

有些编译器可能会被一个编译器混淆,而另一个编译器可能会混淆。

第一个优点是你正在迭代索引元素。

第二个优点是你正在模仿“现代”C ++迭代器语法。 (但是,我会尝试使用!=而不是<,因为比较一个结构过去的指针是未定义的行为,所以你应该确定停在结束,不要吹过它。)

您的问题的真正问题在于它几乎肯定是预先成熟的优化。如果它不是预先成熟的优化,你应该确定这个代码是一个性能瓶颈,你应该分析并确定哪个更快,而不是寻找经验法则。

在“编写不过早悲观的代码”的层面上,都没有真正获胜。清晰度的重要性胜过您将体验到的任何性能差异。清晰度对于性能很重要,因为清晰,易于理解的代码更容易优化,定向优化(在您遇到性能瓶颈并使其性能更好的情况下)比使用不必要的代码读取不清楚的代码更好地利用了性能改进时间微观优化。