- 当我们使用指针和双指针访问内存位置时,有什么性能差异吗?
- 如果是这样,哪个更快?
4 回答
没有简单的答案,因为答案可能取决于实际机器。如果我没记错的话,一些旧机器(例如PDP11)在一条指令中提供了“双指针”访问。
然而,今天的情况并非如此。由于虚拟内存,访问内存并不像看起来那么简单,并且需要大量工作。出于这个原因——我的猜测是,在大多数现代机器上,双重引用实际上应该更慢——需要做更多的工作来将两个地址从虚拟地址转换为物理地址并检索它们——但这只是有根据的猜测。
但是请注意,编译器可能已经为您优化了“冗余”访问。
然而,据我所知,没有任何机器的 'double access' 比 'single access' 更快,所以我们可以说single access 并不比 double access 差。
作为旁注,我相信在现实生活中的程序中,差异是可以忽略的(与程序中所做的任何其他事情相比),除非在对性能非常敏感的循环中完成 - 只做任何更具可读性的事情。此外,如果可以的话,编译器可能已经为您优化了它。
假设你在谈论类似的东西
int a = 10;
int *aptr = &a;
int **aptrptr = &aptr;
那么费用
*aptr = 20;
是一种解引用。必须首先检索指向的地址aptr
,然后才能将地址存储到。
的代价
**aptrptr = 30;
是两个取消引用。aptrptr
必须首先检索指向的地址。然后必须检索存储在该地址中的地址。然后可以将这个地址存储到。
这是你问的吗?
因此,如果适合您的需要,使用单个指针得出结论会更快。
请注意,例如,如果您在循环中访问指针或双指针,
while(some condition)
*aptr = something;
或者
while(some condition)
**aptrptr = something;
编译器可能会进行优化,以便在循环开始时仅执行一次取消引用,因此成本仅为 1 次额外的地址提取而不是 N,其中 N 是循环执行的次数。
编辑:(1)正如 Amit 正确指出的那样,指针访问的“方式”并不是明确的 C 事物……它确实取决于底层架构。如果您的机器支持将双重取消引用作为单个指令,那么可能不会有很大的不同。他以PDP11的索引延迟寻址模式为例。您可能会发现这样的指令仍然会占用更多的周期......请参阅硬件文档并查看您的 C 编译器能够为您的特定架构应用的优化。
PDP11架构大约是 1970 年代。据我所知(如果有人知道现代架构可以做到这一点,请发帖!),大多数 RISC 架构并没有这样的双重取消引用,据我所知,可能需要进行两次提取。
因此,通常使用单个指针得出结论可能更快,但需要注意的是,特定架构可能比其他架构更好地处理这个问题,正如我所讨论的,编译器优化可能会使差异可以忽略不计......以确保你只需要分析你的代码并阅读你的架构:)
让我们这样看:
int var = 5;
int *ptr_to_var = &var;
int **ptr_to_ptr = &ptr;
访问变量 时,
var
您需要- 1.获取变量的地址
- 2.从那个地址获取它的值。
如果是指针
ptr_to_var
,您需要- 1.获取指针变量的地址
- 2.从该地址获取其值(即变量的地址
var
) - 3.获取指向地址的值。
在第三种情况下,指向
int
变量指针的指针ptr_to_ptr
,您需要- 1.获取指针变量的地址
- 2.从该地址获取其值(即指向变量的指针的地址
ptr_var
) - 3.再次从第二步获取的地址(即变量的地址
var
) 中获取其值 - 4.获取指向地址的值。
所以我们可以说通过指针访问指针变量比指针变量慢,而指针变量又比普通变量访问慢。
我很好奇并设置了以下场景:
int v = 0;
int *pv = &v;
int **ppv = &pv;
我尝试取消引用指针并查看反汇编,它显示以下内容:
int x;
x = *pv;
00B33C5B mov eax,dword ptr [pv]
00B33C5E mov ecx,dword ptr [eax]
00B33C60 mov dword ptr [x],ecx
x = **ppv;
00B33C63 mov eax,dword ptr [ppv]
00B33C66 mov ecx,dword ptr [eax]
00B33C68 mov edx,dword ptr [ecx]
00B33C6A mov dword ptr [x],edx
你可以看到有一个额外的 mov 指令用于解除引用,所以我最好的猜测是:双重解除引用不可避免地会变慢。