2012-09-30 11 views
9

że mam struct zdefiniowane następującozwiększającego członkowie struct

struct my_struct 
{ 
    int num; 
}; 

....

Tutaj mam wskaźnik do my_struct i chcę zrobić przyrost na 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; 

} 

Czy te 3 sposoby zwiększania wartości to num zrobić to samo? Podczas gdy jesteśmy przy tym, czy to prawda, że ​​pre-increment jest bardziej wydajny niż post-inkrement?

Dzięki!

Odpowiedz

8

Pierwsze dwa będą miały taki sam efekt (gdy są w takiej samej linii), ale trzecia metoda nie jest poprawnym kodem C (nie można tam umieścić ++).

Jeśli chodzi o efektywność, nie ma różnicy. Różnica, o której słyszeliście, o czym rozmawiają ludzie, polega na tym, że w C++ zwiększa się typ danych niezwiązanych ze wskaźnikiem, taki jak iterator. W niektórych przypadkach pre-increment może być tam szybszy.

Możesz zobaczyć wygenerowany kod za pomocą GCC Explorer.

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

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

wyjściowa:

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

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

Jak widać, nie ma żadnej różnicy.

Jedynym możliwym różnica między pierwszymi dwoma jest, kiedy ich używać w wyrażeniach:

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

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

Jeśli tylko zamiarem jest, aby zwiększyć wartość num wtedy 1 i 2 metoda przyniesie taki sam rezultat odnie do metoda callee.

Jeśli jednak zmienić swój kod Poniżej można zobaczyć różnicę pomiędzy kodem generowanym przez GCC (kod poziomu montażowego):

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

Teraz skompilować go za pomocą: gcc -masm = intel - S structTest.c -o structTest.s Prosi gcc o wygenerowanie kodu zespołu:

Otwórz structTest.s w edytorze tekstu.

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 

A kiedy zmienić operację preinkrementuj kod follwoing jest generowany:

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 

Tak, to widać, że w tym drugim przypadku, kompilator zwiększa wartość num i podań na tej wartości num do printf().

Pod względem wydajności, oczekuję, że przyrost wartości będzie bardziej wydajny, ponieważ lokalizacje pamięci są dotykane mniej razy.

Ważne linie zostały oznaczone między ** w powyższym kodzie.

Powiązane problemy