C/C++:什么更快:for 循环,或增加一个指针

lcm*_*lin 5 c c++ performance pointers loops

我想知道以下哪个代码段最快,假设目标是从指向的T数量类型的元素中读取并用它们做一些事情。我对循环结构本身的效率特别感兴趣,而不是对元素做了什么。numElementssomePointer

第一候选人

for (int i = 0; i < numElements; i++) {
    T val = somePointer[i];
    ... // Do something
}
Run Code Online (Sandbox Code Playgroud)

第二候选人

T* tempPointer = somePointer;
T* endPointer = somePointer + numElements;
while (tempPointer < endPointer) {
    T val = *tempPointer;
    ... // Do something
    tempPointer++;
}
Run Code Online (Sandbox Code Playgroud)

当然,第一个候选更清晰,更不容易出错。但是,如果它实际上被编译成它似乎会生成的代码,我认为它会更慢。使用for循环需要i每次循环迭代的增量,以及在取消引用之前somePointer由 amount指向的地址的偏移量i * sizeOf(t)。指针递增方法似乎每个循环周期只需要一个加法操作,因此让我相信它会更快。

但是,据我所知,编译器尝试for使用 SIMD 指令对循环进行矢量化;如果编译器可以成功地检测到在for循环中进行矢量化的机会但不能使用递增指针,for那么 then 似乎是更快的选择。当然,就我所知,编译器正在检测for循环可以转换为指针增量的情况,并在向量化之前进行转换,这将使它变得无关紧要。

简而言之,在实际场景中,哪个更快?

aut*_*tic 6

从理论上讲,您的问题的答案是前一个更简单的代码。

如果实际实现可以推断出其值未被使用并且不会产生所需的副作用(包括由调用函数或访问易失性对象引起的任何副作用),则实际实现不需要评估表达式的一部分。

这是 C 标准的引用,展示了编译器进行优化的能力。在这种情况下,表达式中不需要的部分与索引相关int(可能应该是 a size_t)。

实际上,您的问题的答案也是以前的更简单的代码。您可能会惊喜地发现当今的常见编译器可以非常轻松执行优化,例如您提到的优化(而且更复杂) 。然而,由于计算机系统的许多方面结合在一起构建了更大的性能图景,因此不可能给出哪个方面更快的答案......我们需要了解有关您的实施的每个相关方面(CPU、内存、操作系统、编译器等)。

请参阅“它会优化吗?” ,一些 gcc 很高兴优化的类似例子。这是循环不变计算优化的一种形式。确保在启用完全优化的情况下编译代码(-O3通常为 )。

然而,您需要考虑的不仅仅是优化。正如您所提到的,前者更简单的代码更容易阅读。这对于任何可能最终维护您的代码的人来说都很重要。

在考虑优化时,这里有一个方便的提示:您的老板会希望看到一些可行的方法,即使它太慢,也宜早不宜迟。如果你没有老板,那太好了!考虑到如果没有可比较的东西,您就无法测量优化的代码,但是......

出于可维护性的目的,编写清晰、简洁的代码。如果您的老板(或您的团队,或您自己,或其他什么)决定完成时速度不够快,请使用您的分析器来确定最重要的瓶颈在哪里,那么您应该知道要关注什么......您将优化您的时间代码。

完成优化后,再次使用分析器来确定优化是否有效。这样您就可以消除猜测可能产生的负面影响。

当今的常见编译器通常甚至可以根据分析器的输出执行优化。这种技术称为“配置文件引导优化”,可能值得研究......