2012-09-30 3 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; 

} 

num의 3 가지 방법으로 동일한 작업을 수행합니까? 이전의 증가가 포스트 증가보다 더 효율적이라는 것은 사실입니까?

감사합니다.

답변

8

첫 번째 두 개는 같은 효과가 있지만 세 번째 방법은 유효한 C 코드가 아닙니다 (이 경우 ++을 넣을 수 없습니다).

효율면에서 차이는 없습니다. C++에서 반복 자 (iterator)와 같은 포인터가 아닌 데이터 유형을 증가시킬 때 사람들이 이야기하는 차이점이 있습니다. 사전 증분이 더 빠른 경우도 있습니다.

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 

는 전혀 차이가 없습니다. 유일한 의도는 NUM의 값을 증가하는 경우

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

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

후 1 차 및 2 차 방법은 동일들이 의도 결과로를 얻을 것입니다 : 당신이 표현에서 사용할 때

처음 두 사이에만 가능 차이점은 피 호출자 메서드 당신이 다음에 코드를 변경하는 경우

그러나, 당신은 GCC (어셈블리 레벨 코드)에 의해 생성 된 코드의 차이를 볼 수 있습니다

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 

가 그리고, 때라도 코드가 생성됩니다

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 값과 패스를 증가 이 num 값에 printf().

성능 측면에서 볼 때, 메모리 위치가 적은 횟수로 터치되기 때문에 포스트 인크 리먼 트가 더 효율적이라고 기대합니다.

위의 코드에서 ** 사이에 중요한 줄이 표시되었습니다.

관련 문제