2014-04-10 3 views
1

배열 내의 구조체에 액세스하여 여러 필드를 수정한다고 가정 해 보겠습니다. 난 항상 두 번째 방법은 "더 나은 것을 가정참조와 배열 색인간에 차이가 있습니까?

unitStruct& unit = units[unitIndex]; 
unit.field1 = value1; 
unit.field2 = value2; 
unit.field3 = value3; 
... 

: 당신은 거기에서을 수정 한 후 구조체에 대한 참조를 당긴 수

units[unitIndex].field1 = value1; 
units[unitIndex].field2 = value2; 
units[unitIndex].field3 = value3; 
... 

또는 : 당신은, 그래서 직접 할 수 ", 그것은 구조체를 다시 찾을 때마다 배열에 인덱스 할 필요가 없다는 것을 의미합니다.

하지만 생각해 보려고 멈추었을 때 컴파일러가 배열 인덱스를 포인터로 구현하는 것 같습니다. 또한 참조는 포인터로 구현 될 가능성이 큽니다. 어쩌면 그들은 내부적으로 같은 일을하고 있을까요?

그래서 내가 궁금한 건, 생성 된 코드 측면에서 컴파일러의 관점에서 볼 때,이 두 가지 방법 사이에 실제적인 차이점이 있습니까? 컴파일러는 이러한 메소드 중 하나에 대한 추가 코드를 생성합니까? 아니면 정확히 동일한 결과를 얻는 두 가지 방법입니까?

답변

2

최적화가 활성화 된 상태에서 컴파일하면 컴파일러에서 같은 코드를 생성하므로 코드를 유지 관리하는 사용자와 코드를 더 쉽게 읽을 수있는 스타일을 사용해야합니다. 예를 들어

#include <cstddef> 
#include <vector> 

struct unitStruct { 
    int field1; 
    int field2; 
    int field3; 
}; 

void noref(std::vector<unitStruct> & units, size_t unitIndex, int value1, int value2, int value3) 
{ 
    units[unitIndex].field1 = value1; 
    units[unitIndex].field2 = value2; 
    units[unitIndex].field3 = value3; 
} 

void ref(std::vector<unitStruct> & units, size_t unitIndex, int value1, int value2, int value3) 
{ 
    unitStruct& unit = units[unitIndex]; 
    unit.field1 = value1; 
    unit.field2 = value2; 
    unit.field3 = value3; 
} 

의 gcc로 컴파일 및 최적화 -O3

g++ -O3 -c struct.cpp -o struct.o 
objdump -D struct.o|less 

같은 코드가 생성 가능 - 처음 세 개의 지침은 다른 순서로 나타납니다,하지만 그것 뿐이다 :

0000000000000000 <_Z5norefRSt6vectorI10unitStructSaIS0_EEmiii>: 
    0: 48 8d 04 76    lea (%rsi,%rsi,2),%rax 
    4: 48 8b 37    mov (%rdi),%rsi 
    7: 48 8d 04 86    lea (%rsi,%rax,4),%rax 
    b: 89 10     mov %edx,(%rax) 
    d: 89 48 04    mov %ecx,0x4(%rax) 
    10: 44 89 40 08    mov %r8d,0x8(%rax) 
    14: c3      retq 

0000000000000020 <_Z3refRSt6vectorI10unitStructSaIS0_EEmiii>: 
    20: 4c 8b 0f    mov (%rdi),%r9 
    23: 48 8d 04 76    lea (%rsi,%rsi,2),%rax 
    27: 49 8d 04 81    lea (%r9,%rax,4),%rax 
    2b: 89 10     mov %edx,(%rax) 
    2d: 89 48 04    mov %ecx,0x4(%rax) 
    30: 44 89 40 08    mov %r8d,0x8(%rax) 
    34: c3      retq 
+0

최적화는 -O3과 함께 사용 가능합니다. –

+0

@RobK 좋은 지적, 나는 그것을 강조 할께, 고마워. – amdn

0

나는 거의 믿을 수 없다. 다시 차이가 있습니다. units[unitIndex]은 unitStruct &을 제공합니다.

누군가가 코드를 읽을 때 유일한 차이점이 있다고 생각합니다.

1

디버그 모드에서 컴파일러는 다른 코드를 생성 할 수 있습니다. 단위 [unitIndex]의 경우 각 행의 단위 + unitIndex 포인터를 계산할 수 있습니다. 참조를 사용하면 오프셋이 한 번 계산되어 스택에 저장됩니다.

최적화 된 빌드에서 컴파일러는 계산을 한 번 수행하고 계산 된 오프셋을 레지스터에 보관합니다.

중요한 것은 더 읽기 쉽고 유지 보수가 용이하다는 점입니다. 당신이 한 가지를 위해 최적화 할 때, 당신은 다른 것을 위해 비관적입니다. 대부분의 경우 가독성과 유지 보수성을 위해 최적화해야합니다.

[ETA] 만약 당신이 그 차이에 대해 정말로 궁금하다면, 컴파일러가 생성 된 어셈블리를 파일에 기록하게 할 수 있습니다. 이를 수행하는 방법에 대해서는 컴파일러의 도움말을 참조하십시오.

관련 문제