2012-09-30 15 views
9

dire che ho uno struct definito come seguedi incremento membri struct

struct my_struct 
{ 
    int num; 
}; 

....

Qui ho un puntatore a my_struct e voglio fare un incremento su 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; 

} 

Questi 3 modi di incrementare num fanno la stessa cosa? Mentre ci siamo, è vero che il pre-incremento è più efficiente del post-incremento?

Grazie!

risposta

8

I primi due avranno lo stesso effetto (quando su una linea in modo proprio così), ma il terzo metodo non è un codice C valido (non è possibile inserire lo ++ lì).

Per quanto riguarda l'efficienza, non c'è differenza. La differenza di cui potresti aver sentito parlare è quando, in C++, si incrementa un tipo di dati non puntatore, come un iteratore. In alcuni casi, il pre-incremento può essere più veloce lì.

È possibile visualizzare il codice generato utilizzando GCC Explorer.

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

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

uscita:

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

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

Come si può vedere, non c'è alcuna differenza.

L'unica possibile differenza tra i primi due è quando si utilizzano nelle espressioni:

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

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

Se la tua unica intenzione è quella di incrementare il valore di num poi il 1 ° e 2 ° metodo produrrà lo stesso risultato intented a il metodo del callee.

Tuttavia, se si cambia il codice di seguito, si può vedere la differenza tra il codice generato da gcc (codice livello di assieme):

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

Ora compilarlo usando: gcc -masm = intel - S structTest.c -o structTest.s Questo chiede gcc per generare il codice assembly:

Aprire structTest.s in un editor di testo.

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 

E quando si cambia l'operazione di pre-incremento, il codice follwoing viene generato:

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 

Quindi, si vedrebbe che nel secondo caso, il compilatore incrementa il valore num e passaggi su questo valore numerico per printf().

In termini di prestazioni, mi aspetto che il post-incremento sia più efficiente poiché le posizioni di memoria vengono toccate un numero inferiore di volte.

Le linee importanti sono state contrassegnate tra ** nel codice precedente.

Problemi correlati