2012-09-30 103 views
9

說我有定義爲結構如下遞增結構成員

struct my_struct 
{ 
    int num; 
}; 

....

在這裏,我有一個指針my_struct,我希望做一個增量num

void foo(struct my_struct* my_ptr) 
{ 
    // increment num 
    // method #1 
    my_ptr->num++; 

    // method #2 
    ++(my_ptr->num); 

    // method #3 
    my_ptr->++num; 

} 

做這3種遞增方式num做同樣的事情? 雖然我們認爲,預增加比後增量更有效嗎?

謝謝!

回答

8

前兩個將會有同樣的效果(當像這樣在一條線上時),但第三個方法不是有效的C代碼(不能將++放在那裏)。

至於效率,沒有區別。你可能聽說過人們談論的區別是,在C++中,你增加了一個非指針數據類型,比如迭代器。在某些情況下,預增量可能會更快。

您可以使用GCC Explorer查看生成的代碼。

void foo(struct my_struct* my_ptr) 
{ 
    my_ptr->num++; 
} 

void bar(struct my_struct* my_ptr) 
{ 
    ++(my_ptr->num); 
} 

輸出:

foo(my_struct*):      # @foo(my_struct*) 
    incl (%rdi) 
    ret 

bar(my_struct*):      # @bar(my_struct*) 
    incl (%rdi) 
    ret 

正如你所看到的,有沒有任何區別。

第一兩者之間的唯一可能不同的是,當你在表達式中使用它們:

my_ptr->num = 0; 
int x = my_ptr->num++; // x = 0 

my_ptr->num = 0; 
int y = ++my_ptr->num; // y = 1 
2

如果你唯一的目的是增加num的值,則第1和第2個方法會產生相同的intented結果被調用方法。

但是,如果你改變你的代碼下面,你可以看到由海灣合作委員會(彙編級代碼)生成的代碼之間的區別:

struct my_struct 
{ 
    int num; 
}; 

void foo(struct my_struct* my_ptr) 
{ 
     printf("\nPost Increment: %d", my_ptr->num++); 
} 

int main() 
{ 
     struct my_struct a; 
     a.num = 10; 

     foo(&a); 
} 

現在使用編譯:GCC -masm =英特爾 - S structTest.c -o structTest.s 這要求gcc生成彙編代碼:

在文本編輯器中打開structTest.s。

foo: 
.LFB0: 
     push rbp 
     mov  rbp, rsp 
     sub  rsp, 16 
     **mov  QWORD PTR [rbp-8], rdi** 
     mov  rax, QWORD PTR [rbp-8] 
     mov  eax, DWORD PTR [rax] 
     mov  edx, eax 
     **lea  ecx, [rax+1]** 
     mov  rax, QWORD PTR [rbp-8] 
     mov  DWORD PTR [rax], ecx 
     mov  eax, OFFSET FLAT:.LC0 
     mov  esi, edx 
     mov  rdi, rax 
     mov  eax, 0 
     call printf 
     leave 
     ret 
     .cfi_endproc 

main: 
.LFB1: 
     push rbp 
     mov  rbp, rsp 
     sub  rsp, 16 
     **mov  DWORD PTR [rbp-16], 10 
     lea  rax, [rbp-16] 
     mov  rdi, rax 
     call foo** 
     leave 
     ret 
     .cfi_endproc 

而當你改變操作預增量,產生follwoing代碼:

foo: 
.LFB0: 
     .cfi_startproc 
     push rbp 
     mov  rbp, rsp 
     sub  rsp, 16 
     **mov  QWORD PTR [rbp-8], rdi** 
     mov  rax, QWORD PTR [rbp-8] 
     mov  eax, DWORD PTR [rax] 
     **lea  edx, [rax+1]** 
     mov  rax, QWORD PTR [rbp-8] 
     **mov  DWORD PTR [rax], edx** 
     mov  rax, QWORD PTR [rbp-8] 
     **mov  edx, DWORD PTR [rax]** 
     mov  eax, OFFSET FLAT:.LC0 
     mov  esi, edx 
     mov  rdi, rax 
     mov  eax, 0 
     call printf 
     leave 
     ret 
     .cfi_endproc 

所以,你會看到,在第二種情況下,編譯器增加NUM值和通行證在這個數值上printf()。

就性能而言,我期望後增加更有效率,因爲內存位置觸及的次數更少。

上述代碼中**之間的重要行已被標記。