繁体   English   中英

什么使指针比数组更快?

[英]What makes pointers faster than arrays?

我在Google上搜索并找到了以下指针语法

  void main()
 {
  char a[10]="helloworld";
  char *p=a;
  printf("%c",p[0]);
 }

我不知道Pointers也可以以数组形式访问。 我曾经使用*作为指针操作我使用[0]表示数组而* p表示指针操作,这就是为什么我不知道其他两件事。 从上面可以看出,我们可以通过以下任何一种方式访问​​数组的第二个元素

  printf("%C",a[1]);   \\ this is the array
  printf("%c",*(a+1));  \\ this is the array using *
  printf("%c", p[1]);     \\ using the pointer 
  printf("%C",*(p+1));    \\ using the pointer

现在我想知道:哪个操作更快? 我读到使用指针的操作更快,这就是为什么C保持在顶部以便快速执行并且没有其他语言能够超越其坚固性的原因。

现在真正的问题是:什么使指针操作更快?

1)*(p + 0)*(地址的值)制作技巧或

2)p [0]

因为我们使用

 *(a+1) or *(p+1) both are same 
  a[1] or p[1] both are same 

当一个普通数组可以用作*(a + 1)(在地址上使用*值)时,就像指针一样。 为什么我们使用指针来加快操作? 当两者具有相同的语法时,正常数组和指针在这些语法中使用*时为什么指针更快?

但伙计们请告诉我为什么我们使用指针? 我的教授告诉我指针更快,因为他们指向地址而不是应该在该位置搜索变量。

我实际上不希望*(ptr + offset)ptr[offset]快。 实际上,在我的机器上,以下函数被编译成完全相同的汇编代码:

int
ArrayRef(int* array, int index)
{
    return array[index];
}

int
PointerRef(int* array, int index)
{
    return *(array + index);
}

哪个(清理过)看起来像:

ArrayRef:
    pushq   %rbp
    movq    %rsp, %rbp
    movq    %rdi, -8(%rbp)
    movl    %esi, -12(%rbp)
    movl    -12(%rbp), %eax
    cltq
    salq    $2, %rax
    addq    -8(%rbp), %rax
    movl    (%rax), %eax
    leave
    ret

PointerRef:
    pushq   %rbp
    movq    %rsp, %rbp
    movq    %rdi, -8(%rbp)
    movl    %esi, -12(%rbp)
    movl    -12(%rbp), %eax
    cltq
    salq    $2, %rax
    addq    -8(%rbp), %rax
    movl    (%rax), %eax
    leave
    ret

(gcc 4.5.0,x86_64,没有优化)。 或者使用-O3

ArrayRef:
    movslq  %esi, %rsi
    movl    (%rdi,%rsi,4), %eax
    ret

PointerRef:
    movslq  %esi, %rsi
    movl    (%rdi,%rsi,4), %eax
    ret

如果阵列在本地堆栈作用域或静态存储器中分配,则阵列访问速度更快,因为它可以通过EBP寄存器中的值的偏移量或通过固定地址的直接偏移量直接访问,而不是尝试访问堆栈变量中指针的值,然后添加到该变量的值并解除引用。

例如,如果你写的数组如下:

int main()
{
    int array[5] = {1, 2, 3, 4, 5};
    //... more code

    return 0;
}

为了访问array[3]的值,编译器只会发出一个简单的命令(这是针对x86):

MOV -8(%ebp), %eax

这是因为如果我们查看堆栈,我们会看到以下内容:

EBP + 4 : Return Address
EBP     : Previous function's stack activation record
EBP - 4 : array[4]
EBP - 8 : array[3]
EBP - 12: array[2]
EBP - 16: array[1]
EBP - 20: array[0]

因此,为了访问array[3]的值,只需要一条指令。 那很快。

在您提供的示例中, p[1]不会比a[1]快。

数组名称本质上是指向该数组的第一个元素的指针 - 因此,它们应该几乎相同。

静态创建的数组有自己的类型,它包含了编译时定义的大小,这使得它们在技术上与指针不同,但是对于所有密集的目的,示例中的数组名称和字符指针可以相同地使用。

数组指针, pa之后没有区别

char a[10]="helloworld";
char *p=a;

ap都是指向char的指针,它们指向同一个地方 - 数组在内存中的开头

使用“operator []”也等同于指针算术

a[i] 

将被替换为

*(a+i)

这意味着指向数组开头的指针将被i * sizeof(char)移动到数组的第i个元素的位置。

当您尝试遍历所有元素时,会出现真正的时间差异,例如,复制字符串:

char a[10] = "helloworld";
char b[10];
for (int i = 0; i < 10; ++i) b[i] = a[i]; // using array element accessing method

对于循环的每次迭代,将产生类似b + i(又名为b by i * sizeof(char))和a + i(也称为i * sizeof(char)的移位)的算术,以及

char a[10] = "helloworld";
char b[10];
char *_a, *_b;
for (_a = a, _b = b; *_a != '\0'; ++_a, ++_b) *_a = *_b; // using pointers arithmetic method
*b = '\0';

从这些计算中解脱出来,每次只能按char的大小移动两个指针。

比数组更快的指针来自以下示例。

假设您要实现strcpy函数,即将一个以null结尾的字符串复制到另一个字符串。 我们来看两个例子:

第一:

char* strcpy(char* dest, const char* src)
{
    int i = 0;
    while( src[i] != '\0' ) {
        dest[i] = src[i];
        i++;
    }
    dest[i] = '\0';

    return dest;
}

第二个:

char* strcpy(char* dest, const char* src)
{
    char *save = dest;
    while( *src != '\0' )
    {
        *dest++ = *src++;
    }
    *dest = '\0';

     return save;
}

第二个示例更有效地实现,因为它在每次迭代中执行的内存修改更少,并且它使用指针而不是数组。 但有两件事:

  1. 它不是快速的指针,它是使用它们进行优化的算法。
  2. 优化器可以轻松地自动执行这种优化,因此您最终可能会得到相同的生成代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM