为什么我的数组索引比指针快

use*_*648 11 c arrays indexing pointers

为什么数组索引比指针快?指针不应该比数组索引快吗?

**我使用time.h clock_t来测试两个函数,每个函数循环200万次.

Pointer time : 0.018995

Index time : 0.017864

void myPointer(int a[], int size)
{
     int *p;
     for(p = a; p < &a[size]; p++)
     {
         *p = 0;
     }
}


void myIndex(int a[], int size)
{
     int i;
     for(i = 0; i < size; i++)
     {
         a[i] = 0;
     }
}
Run Code Online (Sandbox Code Playgroud)

mos*_*ear 5

数组取消引用p[i]*(p + i). 编译器利用在 1 或 2 个周期内执行数学 + 解引用的指令(例如 x86 LEA 指令)来优化速度。

使用指针循环,它将访问和偏移量分成单独的部分,编译器无法对其进行优化。


Ron*_*Ron 5

可能是 for 循环中的比较导致了差异。每次迭代都会测试终止条件,并且您的“指针”示例具有稍微复杂一些的终止条件(取 &a[size] 的地址)。由于 &a[size] 不会改变,您可以尝试将其设置为变量以避免在循环的每次迭代中重新计算它。


min*_*ang 5

不,永远不会指针比数组索引更快.如果其中一个代码比另一个快,那主要是因为某些地址计算可能不同.该问题还应该提供编译器和优化标志的信息,因为它会严重影响性能.

上下文中的数组索引(数组绑定未知)与指针操作完全相同.从编译器的角度来看,它只是指针算法的不同表达.以下是Visual Studio 2010中优化的x86代码示例,该代码具有完全优化无内联.

     3: void myPointer(int a[], int size)
     4: {
013E1800  push        edi  
013E1801  mov         edi,ecx  
     5:      int *p;
     6:      for(p = a; p < &a[size]; p++)
013E1803  lea         ecx,[edi+eax*4]  
013E1806  cmp         edi,ecx  
013E1808  jae         myPointer+15h (13E1815h)  
013E180A  sub         ecx,edi  
013E180C  dec         ecx  
013E180D  shr         ecx,2  
013E1810  inc         ecx  
013E1811  xor         eax,eax  
013E1813  rep stos    dword ptr es:[edi]  
013E1815  pop         edi  
     7:      {
     8:          *p = 0;
     9:      }
    10: }
013E1816  ret 

    13: void myIndex(int a[], int size)
    14: {
    15:      int i;
    16:      for(i = 0; i < size; i++)
013E17F0  test        ecx,ecx  
013E17F2  jle         myIndex+0Ch (13E17FCh)  
013E17F4  push        edi  
013E17F5  xor         eax,eax  
013E17F7  mov         edi,edx  
013E17F9  rep stos    dword ptr es:[edi]  
013E17FB  pop         edi  
    17:      {
    18:          a[i] = 0;
    19:      }
    20: }
013E17FC  ret 
Run Code Online (Sandbox Code Playgroud)

一目了然,myIndex看起来更快,因为指令的数量较少,但是,这两段代码基本相同.两者最终都使用rep stos,这是x86的重复(循环)指令.唯一的区别是因为循环边界的计算.在for中环myIndex有行程计数size,因为它是(即,不需要计算).但是,myPointer需要一些计算来获得for循环的行程计数.这是唯一的区别.重要的循环操作是一样的.因此,差异可以忽略不计.

总而言之,优化代码的性能myPointermyIndex优化代码应该相同.


FYI,如果数组的绑定在编译时是已知的,例如int A[constant_expression],那么对该数组的访问可能比指针1快得多.这主要是因为数组访问没有指针分析问题.编译器可以完美地计算固定大小数组上的计算和访问的依赖性信息,因此它可以进行高级优化,包括自动并行化.

但是,如果计算是基于指针的,则编译器必须执行指针分析以进一步优化,这在C/C++中非常有限.它通常在指针分析上得到保守的结果,并导致一些优化机会.