簡體   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