2012-09-30 11 views
9

Sagen, ich habe eine Struktur definiert alsInkrementieren struct Mitglieder

struct my_struct 
{ 
    int num; 
}; 

....

Hier folgt habe ich einen Zeiger auf my_struct und ich möchte auf einen Zuwachs tun 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; 

} 

Müssen diese drei Arten der Inkrementierung num das gleiche tun? Während wir dabei sind, ist es wahr, dass Pre-Inkrement ist effizienter als Post-Inkrement?

Danke!

Antwort

8

Die ersten beiden haben den gleichen Effekt (wenn auf einer eigenen Zeile so), aber die dritte Methode ist nicht gültig C-Code (Sie können die ++ dort nicht setzen).

Hinsichtlich der Effizienz gibt es keinen Unterschied. Der Unterschied, über den Sie vielleicht schon einmal gehört haben, ist, dass Sie in C++ einen Nicht-Zeiger-Datentyp, z. B. einen Iterator, inkrementieren. In einigen Fällen kann das Vorinkrement dort schneller sein.

Sie können den generierten Code mit GCC Explorer sehen.

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

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

Ausgang:

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

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

Wie Sie sehen können, gibt es keinen Unterschied überhaupt.

Die einzig mögliche Differenz zwischen den ersten beiden ist, wenn man sie in Ausdrücken verwenden:

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

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

Wenn Ihre einzige Absicht, den Wert von num zu erhöhen, ist dann der 1. und 2. Methode gleiche intented Ergebnis liefern zu die aufgerufene Methode.

Wenn Sie jedoch Ihren Code auf die folgenden ändern, können Sie den Unterschied zwischen dem Code sehen von gcc (Baugruppenebene Code) generiert:

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); 
} 

es jetzt kompilieren mit gcc -masm = Intel - S structTest.c -o structTest.s Dies fragt GCC, um den Assembly-Code zu generieren:

Öffnen Sie structTest.s in einem Texteditor.

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 

Und wenn man den Betrieb ändern zu Schritt vor, wird der follwoing Code generiert:

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 

Also, Sie, dass im zweiten Fall sehen würden, erhöht der Compiler den num Wert und Pässe auf diesen num-Wert für printf().

In Bezug auf die Leistung würde ich erwarten, dass das Post-Inkrement effizienter ist, da die Speicherorte weniger oft berührt werden.

Die wichtigen Zeilen wurden im obigen Code zwischen ** markiert.