aja*_*xhe 6 c assembly visual-studio-2010
有些人说:"任何可以通过数组下标实现的操作也可以通过指针来完成.指针版本通常会更快".
我怀疑上面的结果,所以我做了以下测试:
在下面的文章中,我们不关心编译器优化.关于编译器优化如何影响指针和数组之间的效率,请注意:效率:数组与指针
(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;
}
Run Code Online (Sandbox Code Playgroud)
结果是:
10 billion times of *ap = 3276
10 billion times of a[0] = 3541
Run Code Online (Sandbox Code Playgroud)
指针似乎有点快.但是在我对比拆解后,我陷入了更深层次的困惑.
(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
Run Code Online (Sandbox Code Playgroud)
从汇编输出,通过指针的存储器访问需要2条指令,而数组只需要1条指令.
为什么数组执行较少的指令,但它不比指针花费更少的时间?
它与cpu缓存有关吗?如何修改我的测试代码来证明它?
首先也是最重要的是,C 语言没有速度。这是 C 的实现引入的一个属性。例如,C 没有速度,但 GCC 编译器生成的代码可能与 Clang 编译器生成的代码在速度上有所不同,并且它们都可能生成的代码的性能优于 Cint 或 Ch 解释器生成的行为。所有这些都是 C 实现。其中一些比其他的慢,但是速度无论如何不能归因于C!
\n\nC标准的6.3.2.1说:
\n\n\n\n\n除非它是 sizeof 运算符、_Alignof\n 运算符或一元 & 运算符的操作数,或者是用于\n 初始化数组的字符串文字、类型为 \xe2\x80\x98\xe2\ 的表达式\xe2\x80\x99\xe2\x80\x99 类型的 x80\x98 数组\n 转换为 \n 类型为 \xe2\x80\x98\xe2\x80\x98 的表达式,指向类型\xe2\x80\x99\xe2\x80 的指针\x99 指向数组对象的初始元素,并且不是左值。
\n
这应该表明您的代码中的 和 都是*(ap+1)指针操作。此转换将在 Visual Studio 中的编译阶段进行。因此,这不会对运行时产生任何影响。a[1]
6.5.2.1 关于“数组下标”说:
\n\n\n\n\n其中一个表达式应具有类型 \xe2\x80\x98\xe2\x80\x98pointer 来完成对象\n 类型\xe2\x80\x99\xe2\x80\x99,另一个表达式应具有整数类型,结果\ n 的类型为 \xe2\x80\x98\xe2\x80\x98type\xe2\x80\x99\xe2\x80\x99。这似乎表明数组下标\n运算符实际上是一个指针运算符......
\n
正如我们之前假设的那样,这确认了ap[1]确实是指针操作。然而,在运行时,数组已经被转换为指针。性能应该是相同的。
...那么,为什么它们不相同?
\n\n您正在使用的操作系统有哪些特点?它不是一个多任务、多用户操作系统吗?假设操作系统要不间断地完成第一个循环,但随后中断第二个循环并将控制权切换到不同的进程。这种中断不会导致你的实验无效吗?如何衡量任务切换造成的中断的频率和时间?请注意,这对于不同的操作系统会有所不同,并且操作系统是实现的一部分。
\n\n您使用的 CPU 有哪些特性?它有自己的快速机器代码内部缓存吗?假设您的整个第一个循环及其包含的计时机制很好地适合代码缓存,但第二个循环被截断了。这不会导致缓存未命中,并且在 CPU 从 RAM 中获取剩余代码时需要长时间等待吗?如何衡量缓存未命中造成的中断时间?请注意,这对于不同的 CPU 会有所不同,并且 CPU 是实现的一部分。
\n\n这些问题应该提出一些问题,例如“这个微优化基准是否解决了有意义或重要的问题?”。优化的成功与否取决于问题的规模和复杂性。找到一个重要问题,解决它,分析解决方案,优化它并再次分析它。这样,您就可以提供有关优化版本快了多少的有意义的信息。正如我之前提到的,只要您不透露优化可能只与您的实施相关,您的老板会对您感到更加满意。我确信您会发现您最不用担心的是数组取消引用与指针取消引用。
\n| 归档时间: |
|
| 查看次数: |
423 次 |
| 最近记录: |