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

时间:2015-06-10 04:48:53

标签: c++ c performance loops pointers

我想知道以下哪个代码段最快,假设目标是从T指向的numElements量中读取somePointer类型的元素并执行与他们的东西。我对循环结构本身的效率特别感兴趣,而不是对元素做了什么。

第一候选人

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

第二候选人

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

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

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

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

3 个答案:

答案 0 :(得分:3)

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

  

这是       实际实现不需要评估表达式的一部分,如果它可以推导出它       不使用值,不产生任何副作用(包括由...引起的任何副作用)        调用函数或访问volatile对象。)

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

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

请参阅"Will it Optimise?",了解gcc愉快优化的一些类似示例。这是loop invariant computation优化的一种形式。确保在启用完全优化的情况下编译代码(通常为-O3

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

在考虑优化时,这里有一个方便的提示:你的老板会希望看到一些有效的东西,即使它太慢,也不是很晚。如果你没有老板,太好了!考虑到您无法测量优化的代码而无需将其与之进行比较,但是......

为了可维护性而编写清晰,简洁的代码。如果您的老板(或您的团队,或您自己或其他任何人)决定何时完成它的速度不够快,请使用您的探查器确定在最重要的瓶颈所在的地方,你应该知道要关注什么...你将优化你的时间你的代码。

完成优化后,再次使用您的探查器确定它是否是有效的优化。这样您就可以消除猜测可能所带来的负面影响。

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

答案 1 :(得分:1)

作为一般规则,for循环的最坏情况运行时间,以及像这样的while循环是O(n)。也就是说,它会根据您拥有的元素数量线性增长。

在这种情况下,考虑哪一个更快,因为它们基本相同,假设你将在

下做什么,它的价值很小。
//Do something

是一样的。

在考虑程序的效率时,值得考虑运行时间和内存效率。

我认为你的for循环/ while循环中写的内容对于影响你的运行时间的重要性更重要。

希望这有帮助!

答案 2 :(得分:-1)

假设您在intel板上使用GCC或MinGW或Cygwin。 for循环内置支持intel板进行计数器递增现在如果考虑第二个循环,那么指针应该以它所指向的数据类型的大小递增,这将要求编译器将更多代码放入程序集中代码并最终会增加CPU的开销,增加更多的CPU周期来完成你的代码,但在第一种情况下,编译器将生成汇编代码,以便在寄存器本身保持计数器变量i,使CPU易于比较并继续/中断循环如果你把两个代码写在两个文件中(one.c和two.c说)并运行以下命令

gcc -S one.c
gcc -S two.c

查看汇编代码,如果你理解x86汇编,你可以更清楚地理解我想说的内容。我的理解是,如果你深入了解CPU和汇编的工作原理,第一个循环会更快。