有些人说:“任何可以通过数组下标实现的操作也可以用指针完成。指针版本通常会更快”。
我怀疑上述结果,所以我做了以下测试:
在下面的文章中,我们不关心编译器优化。关于编译器优化如何影响指针和数组之间的效率,请注意:Efficiency: arrays vs pointers
(Visual Studio 2010,调试模式,无优化)
#include <windows.h>
#include <stdio.h>
int main()
{
int a[] = {10,20,30};
int* ap = a;
long counter;
int start_time, end_time;
int index;
start_time = GetTickCount();
for (counter = 1000000000L; counter>0; counter--)
{
*(ap+1) = 100;
}
end_time = GetTickCount();
printf("10 billion times of *ap = %d\n", end_time-start_time);
start_time = GetTickCount();
for (counter = 1000000000L; counter>0; counter--)
{
a[1] = 101;
}
end_time = GetTickCount();
printf("10 billion times of a[0] = %d\n", end_time-start_time);
return 0;
}
结果是:
10 billion times of *ap = 3276
10 billion times of a[0] = 3541
指针似乎有点快。 但是在我比较了拆解之后,我陷入了更深的困惑。
(Visual Studio 2010,调试模式,无优化)
; 17 : *(ap+1) = 100;
mov eax, DWORD PTR _ap$[ebp]
mov DWORD PTR [eax+4], 100 ; 00000064H
; 25 : a[1] = 101;
mov DWORD PTR _a$[ebp+4], 101 ; 00000065H
从汇编输出,通过指针的内存访问需要2条指令,而数组只需要1条指令。
为什么数组执行较少的指令但是它不比指针花费更少的时间?
它与cpu缓存有关吗?如何修改我的测试代码以证明它?
答案 0 :(得分:2)
首先也是最重要的是,C语言没有速度。这是由C的实现引入的属性。例如,C没有速度,但GCC编译器生成的代码可能与Clang编译器生成的代码速度不同,并且它们都可能生成代码,执行Cint或Ch解释器生成的行为。所有这些都是C实现。其中一些比其他人慢,但速度不能归因于C !
C标准的6.3.2.1 说:
除非它是sizeof运算符的操作数,否则_Alignof 操作员,或一元&amp;运算符,或者是用于的字符串文字 初始化一个数组,一个类型为''array of type''的表达式 转换为类型为''指向类型'指针的表达式 到数组对象的初始元素,而不是左值。
这应该表明代码中的*(ap+1)
和a[1]
都是指针操作。此转换将在Visual Studio的编译阶段进行。因此,这不会对运行时产生任何影响。
6.5.2.1 说:
其中一个表达式应具有指向完整对象的类型''指针 type'',另一个表达式应该是整数类型,结果 类型''类型''。这似乎表明了数组下标 operator实际上是一个指针运算符......
这是确认ap[1]
确实是指针操作,正如我们之前假设的那样。但是,在运行时,数组已经转换为指针。表现应该相同。
...那么,为什么它们不相同?
您正在使用的操作系统有哪些特征?它不是一个多任务,多用户操作系统?假设操作系统不间断地完成第一个循环,但是然后中断第二个循环并将控制切换到另一个进程。这种中断不会使您的实验无效吗?如何衡量任务切换引起的中断频率和时间?请注意,这对于不同的操作系统会有所不同,操作系统是实现的一部分。
您正在使用的CPU的特征是什么?它是否拥有自己的机器代码快速内部缓存?假设您的整个第一个循环,它包含的计时机制很好地适应代码缓存,但第二个循环被截断。这会不会导致缓存未命中,并且在CPU从RAM中获取剩余代码时会等待很长时间?如何衡量缓存未命中导致的中断时间?请注意,这对于不同的CPU会有所不同,并且CPU是实现的一部分。
这些问题应该提出一些问题,例如“这个微优化基准是否解决了一个有意义或重要的问题?”。优化的成功将根据问题的大小和复杂性而有所不同。找到一个重要问题,解决它,分析解决方案,优化它并再次对其进行分析。这样,您就可以提供有关优化版本的速度的有用信息。如前所述,如果你没有透露优化可能只与你的实现有关,那么你的老板会对你更开心。我相信你会发现你最不担心的是数组取消引用vs指针取消引用。