2012-09-30 28 views
9

Digamos que tiene una estructura definida de la siguiente manerade incremento miembros de la estructura

struct my_struct 
{ 
    int num; 
}; 

....

Aquí tengo un puntero a my_struct y yo quiero hacer un incremento en 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; 

} 

¿Estas 3 maneras de incrementar num hacen lo mismo? Mientras estamos en eso, ¿es cierto que el pre-incremento es más eficiente que el incremento posterior?

Gracias!

Respuesta

8

Los primeros dos tendrán el mismo efecto (cuando en una línea propia así), pero el tercer método no es código C válido (no se puede poner el ++ allí).

En cuanto a la eficiencia, no hay diferencia. La diferencia de la que puede haber oído hablar a las personas es cuando, en C++, incrementa un tipo de datos que no son punteros, como un iterador. En algunos casos, el pre-incremento puede ser más rápido allí.

Puede ver el código generado usando GCC Explorer.

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

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

Salida:

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

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

Como se puede ver, no hay ninguna diferencia en absoluto.

La única diferencia posible entre los dos primero es cuando los utiliza en las expresiones:

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

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

Si su única intención es incrementar el valor de num entonces el primero y el segundo método rendirá mismo resultado intented a el método callee.

Sin embargo, si cambia su código a la siguiente, se puede ver la diferencia entre el código generado por gcc (código de nivel de ensamblado):

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

Ahora compilarlo usando: -masm gcc = Intel - S structTest.c -o structTest.s Esto le pide a gcc que genere el código de ensamblado:

Abra structTest.s en un editor de texto.

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 

Y cuando cambie la operación de pre-incremento, se genera el código 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 

Por lo tanto, se podría ver que en el segundo caso, el compilador incrementa el valor num y pases en este valor num para printf().

En términos de rendimiento, espero que el incremento posterior sea más eficiente ya que las ubicaciones de memoria se tocan menos veces.

Las líneas importantes se han marcado entre ** en el código anterior.

Cuestiones relacionadas