使用指针和双指针访问时的性能差异

时间:2014-02-13 11:28:28

标签: c performance memory memory-access

  1. 使用指针和双指针访问内存位置时是否存在性能差异?
  2. 如果是这样,哪一个更快?

4 个答案:

答案 0 :(得分:7)

没有简单的答案,因为答案可能取决于实际的机器。如果我没记错的话,一些遗留机器(例如PDP11)在一条指令中提供了“双指针”访问。

然而,今天情况并非如此。由于virtual memory,访问内存不像看起来那么简单,需要大量工作。出于这个原因 - 我的猜测是,在大多数现代机器上,双引用实际上应该更慢 - 需要做更多的工作才能将两个地址从虚拟地址转换为物理地址并检索它们 - 但这只是受过教育的猜测。
但请注意,编译器可能已为您优化“冗余”访问

但是,据我所知,没有机器比“单一访问”具有更快的“双重访问权限”,因此我们可以说单一访问并不比双重访问更差

作为旁注,我相信现实生活中的程序,差异是可以忽略的(与程序中的其他任何内容相比),除非在一个性能敏感的循环中完成 - 只需做任何更具可读性的< / strong>即可。此外,如果可以,编译器可能已经为您优化了它。

答案 1 :(得分:5)

假设你在谈论像

这样的事情
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是循环执行次数的numnber。

编辑: (1)正如Amit正确地指出指针访问的“如何”不是显式的C事物......它确实取决于底层架构。如果您的机器支持双重取消引用作为单个指令,那么可能没有太大的区别。他使用index deferred addressing modePDP11作为示例。您可能会发现这样的指令仍然会占用更多周期...请参阅硬件文档并查看C编译器能够应用于特定体系结构的优化。

PDP11架构大约在20世纪70年代。据我所知(如果有人知道现代架构可以做这个请求!),大多数RISC架构并没有这样的双重引用,据我所知,可能需要做两次读取。

因此,使用单个指针得出结论通常可能更快,但有一点需要注意,特定架构可能比其他架构更好地处理这个问题,而正如我所讨论的那样,编译器优化可能会使差异可以忽略不计。 ..确保你只需要描述你的代码并阅读你的架构:)

答案 2 :(得分:1)

让我们以这种方式看待它:

int var = 5;
int *ptr_to_var = &var;
int **ptr_to_ptr = &ptr;
  • 访问变量 var时,您需要

    • 1.getget变量的地址
    • 2.从该地址获取其值。
  • 如果是指针 ptr_to_var,则需要

    • 1.getget 指针变量的地址
    • 2.从该地址获取其值(即变量var的地址)
    • 3.fetch指向的地址的值。
  • 在第三种情况下,指向int 变量ptr_to_ptr指针的指针,你需要

    • 1.getget 指向指针变量的指针
    • 2.从该地址获取其值(即指向变量ptr_var的指针的地址)
    • 3.again从第二步中获取的地址(即变量var的地址)中获取其值
    • 4.fetch指向的地址的值。

所以我们可以说通过指针访问指针变量的速度比指针变量的访问慢,后者又比正常变量访问速度慢。

答案 3 :(得分:1)

我很好奇并设置了以下场景:

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指令用于解除引用,所以我最好的猜测是:双重解除引用不可避免地会更慢。