C++ 使用指针递增1的数组元素进行迭代是否更快?
做这样的事情快吗C++ 使用指针递增1的数组元素进行迭代是否更快?,c++,c,arrays,pointers,optimization,C++,C,Arrays,Pointers,Optimization,做这样的事情快吗 for ( int * pa(arr), * pb(arr+n); pa != pb; ++pa ) { // do something with *pa } (大小k=0;k测量,证明,然后问!为什么你会期望一个现代C++编译器不为完全相同的代码优化??你的代码在C中是非法的,请删除[c]标签,或者编辑代码为有效C。 compute1(int*, int): testl %esi, %esi jle .L4 leal -1(%rs
for ( int * pa(arr), * pb(arr+n); pa != pb; ++pa )
{
// do something with *pa
}
(大小k=0;k
{
//用arr[k]做点什么
}
我知道
arr[k]
相当于*(arr+k)
,但在第一种方法中,您使用的是递增1的当前指针,而在第二种情况下,您使用的是从arr
递增的指针。也许硬件有增加1的特殊方法,所以第一种方法更快?还是不?只是好奇。希望我的问题有意义 这是无法回答的。这取决于编译器和机器
一个非常幼稚的编译器会将代码原样翻译成机器代码。大多数机器确实提供了非常快速的增量操作。它们通常还为带有偏移量的地址提供相对寻址。这可能需要比绝对寻址多几个周期。因此,是的,带有指针的版本可能会更快
但要考虑到每台机器都是不同的,只要程序的可观察行为不变,编译器就可以进行优化。考虑到这一点,我建议一个合理的编译器将从两个版本创建性能没有差异的代码。如果编译器足够智能(大多数编译器都是),那么两个循环的性能应该相等 例如,我在gcc 5.1.0中编译了生成程序集的代码:
int __attribute__ ((noinline)) compute1(int* arr, int n)
{
int sum = 0;
for(int i = 0; i < n; ++i)
{
sum += arr[i];
}
return sum;
}
int __attribute__ ((noinline)) compute2(int* arr, int n)
{
int sum = 0;
for(int * pa(arr), * pb(arr+n); pa != pb; ++pa)
{
sum += *pa;
}
return sum;
}
如您所见,两个函数中最重的部分(循环)相等:
.L9:
addl (%rdi), %eax
addq $4, %rdi
cmpq %rdi, %rdx
jne .L9
rep ret
但在更复杂的示例或其他编译器中,结果可能不同。因此,您应该对其进行测试和度量,但大多数编译器都会生成类似的代码
完整的代码示例:任何合理的编译器都会为这两个选项在循环中生成相同的代码-我查看了在
std::vector
上迭代生成的代码,使用for循环和整数作为迭代器,或者使用for(auto I:vec)
类型构造[std::vector
内部有两个指针用于存储值的begin
和end
,就像您的pa
和pb
]一样。gcc和clang在循环本身内部生成相同的代码[循环的确切细节在编译器之间有细微的差别,但除此之外,没有差别]。循环的设置有细微的差别,但除非您经常执行少于5项的循环[如果是这样,您为什么担心?],否则循环的实际内容才是重要的,而不是实际循环之前的位
与所有性能重要的代码一样,确切的代码、编译器品牌和版本、编译器选项、处理器品牌和型号将对代码的性能产生影响。但对于绝大多数处理器和编译器,我认为没有可测量的差异。如果代码真的很关键,请测量不同的替代方案,并使用E:在你的情况下,什么是最有效的。< /P>测量,证明,然后问!为什么你会期望一个现代C++编译器不为完全相同的代码优化??你的代码在C中是非法的,请删除[c]标签,或者编辑代码为有效C。
compute1(int*, int):
testl %esi, %esi
jle .L4
leal -1(%rsi), %eax
leaq 4(%rdi,%rax,4), %rdx
xorl %eax, %eax
.L3:
addl (%rdi), %eax
addq $4, %rdi
cmpq %rdx, %rdi
jne .L3
rep ret
.L4:
xorl %eax, %eax
ret
compute2(int*, int):
movslq %esi, %rsi
xorl %eax, %eax
leaq (%rdi,%rsi,4), %rdx
cmpq %rdx, %rdi
je .L10
.L9:
addl (%rdi), %eax
addq $4, %rdi
cmpq %rdi, %rdx
jne .L9
rep ret
.L10:
rep ret
main:
xorl %eax, %eax
ret
.L9:
addl (%rdi), %eax
addq $4, %rdi
cmpq %rdi, %rdx
jne .L9
rep ret