x + =가 x = x + a보다 빠릅니까?


84

Stroustrup의 "The C ++ Programming Language"를 읽고 있었는데, 여기서 그는 변수에 무언가를 추가하는 두 가지 방법 중

x = x + a;

x += a;

그는 더 +=잘 구현 될 가능성이 높기 때문에 선호합니다 . 나는 그가 더 빨리 작동한다는 것을 의미한다고 생각합니다.
하지만 정말로 요? 컴파일러 및 기타 사항에 따라 다르면 어떻게 확인합니까?


45
"C ++ 프로그래밍 언어"는 1985 년에 처음 출판되었습니다. 가장 최근 버전은 1997 년에 출판되었고 1997 년 버전의 특별판은 2000 년에 출판되었습니다. 그 결과 일부 부분은 매우 구식입니다.
JoeG

5
두 줄은 잠재적으로 완전히 다른 작업을 수행 할 수 있습니다. 좀 더 구체적이어야합니다.
Kerrek SB


26
최신 컴파일러는 이러한 질문이 '오래된'것으로 간주 될만큼 똑똑합니다.
gd1

2
중복 질문이 C ++가 아닌 C에 대해 묻기 때문에 이것을 다시 열었습니다.
Kev

답변:


212

모든 컴파일러 가치는 소금 정확히 어떤 내장 유형 (모두 구조에 대한 동일한 시스템 언어 시퀀스를 생성 int, float긴 문장이 정말 단순하게만큼, 등) x = x + a; 및 최적화하는 것이 활성화된다 . (특히 -O0기본 모드 인 GCC 는 디버거가 항상 변수 값을 찾을 수 있도록 완전히 불필요한 저장소를 메모리에 삽입하는 것과 같은 최적화 방지를 수행 합니다.)

그러나 진술이 더 복잡하다면 다를 수 있습니다. f포인터를 반환하는 함수 라고 가정 하면

*f() += a;

f한 번만 호출 하는 반면

*f() = *f() + a;

두 번 호출합니다. 경우 f부작용이있다, 둘 중 하나는 (후자 아마) 잘못된 것입니다. 설사f부작용이 컴파일러는 두 번째 호출을 제거하지 못할 수 있으므로 후자는 실제로 더 느릴 수 있습니다.

그리고 우리가 여기서 C ++에 대해 이야기하고 있기 때문에, operator+operator+=. 경우 x최적화하기 전에 - - 다음 같은 유형이다 x += a로 변환

x.operator+=(a);

반면에 x = x + a번역

auto TEMP(x.operator+(a));
x.operator=(TEMP);

이제 클래스가 제대로 작성 되고 컴파일러의 옵티마이 저가 충분하면 둘 다 동일한 기계어를 생성하지만 내장 유형과 같은 확실한 것은 아닙니다. 이것은 아마도 Stroustrup이 +=.


14
가독성이라는 또 다른 측면도 있습니다. 추가 C ++ 관용구 exprvar있다 var+=expr하고 그것을 독자를 혼동 할 다른 방법을 쓰기.
Tadeusz Kopec

21
당신이 쓰는 자신을 발견하면 *f() = *f() + a;당신은 ... 당신이 정말로 무엇을 달성하고 싶은지에 좋은 열심히 살펴 봐야 할 수 있습니다
아담 데이비스에게

3
그리고 var = var + expr이 당신을 혼동하지만 var + = expr은 그렇지 않다면, 당신은 내가 만난 가장 이상한 소프트웨어 엔지니어입니다. 둘 중 하나를 읽을 수 있습니다. 다만 확실히 당신에게 온다면, 일관성있는 (그리고 우리 모두 사용 연산 = 그 논쟁 어쨌든 = P 정도)
WhozCraig

7
@PiotrDobrogost : 질문에 답하는 데 무엇이 문제입니까? 어쨌든 중복 여부를 확인한 사람은 질문자 여야합니다.
Gorpik

4
@PiotrDobrogost는 당신이 조금 ... 질투하는 것처럼 보입니다 ... 중복을 찾고 싶다면, 그것을 찾으십시오. 나는 속임수를 찾는 것보다 질문에 대답하는 것을 선호합니다 (이전에 본 적이있는 질문이 아니라면). 때로는 더 빠를 수 있으며 질문을 더 빨리 한 사람을 ergo 도와줍니다. 또한 이것은 루프가 아닙니다.1상수, a휘발성, 사용자 정의 유형 등이 될 수 있습니다. 완전히 다릅니다. 사실 나는 이것이 어떻게 종결되었는지 이해하지 못한다.
Luchian Grigore

56

동일하게 될 dissasembly를보고 확인할 수 있습니다.

기본 유형의 경우 둘 다 똑같이 빠릅니다.

이것은 디버그 빌드에 의해 생성 된 출력입니다 (예 : 최적화 없음).

    a += x;
010813BC  mov         eax,dword ptr [a]  
010813BF  add         eax,dword ptr [x]  
010813C2  mov         dword ptr [a],eax  
    a = a + x;
010813C5  mov         eax,dword ptr [a]  
010813C8  add         eax,dword ptr [x]  
010813CB  mov         dword ptr [a],eax  

사용자 정의 유형 이 오버로드 할 수 있습니다, operator +그리고 operator +=, 그것은 각각의 구현에 따라 달라집니다.


1
모든 경우에 사실이 아닙니다. 메모리 주소를 레지스터에로드하고, 증가시키고, 메모리 위치를 직접 증가시키는 것보다 다시 쓰는 것이 더 빠를 수 있음을 발견했습니다 (아토 믹스를 사용하지 않음). 코드를 훔쳐 보겠습니다 ...
James

사용자 정의 유형은 어떻습니까? 좋은 컴파일러 동등한 어셈블리를 생성 해야 하지만 그러한 보장은 없습니다.
mfontanini

1
@LuchianGrigore 아니는 경우에 a한하고 x있다 volatile컴파일러가 생성 할 수 있습니다 inc DWORD PTR [x]. 이것은 느립니다.
James

1
@Chiffa는 컴파일러 의존적이지 않지만 개발자 의존적입니다. operator +아무것도하지 않고 operator +=100000 번째 소수를 계산 한 다음 반환하도록 구현할 수 있습니다. 물론 그것은 어리석은 일이지만 가능합니다.
Luchian Grigore

3
@ 제임스 : 프로그램이 사이의 성능 차이를 분별하는 경우 ++xtemp = x + 1; x = temp;대부분의 아마 ++ 조립 오히려 C 이상에서 작성해야 다음, ...
EmirCalabuch

11

예! 후자의 경우 x부작용 이 있을 수있는 경우 쓰기가 더 빠르고 읽기가 더 빠르며 알아내는 것이 더 빠릅니다 . 그래서 인간에게는 전반적으로 더 빠릅니다. 일반적으로 인간의 시간은 컴퓨터 시간보다 훨씬 더 비싸므로 여러분이 요청한 것이 틀림 없습니다. 권리?


8

x와 a의 유형과 +의 구현에 따라 달라집니다. 에 대한

   T x, a;
   ....
   x = x + a;

컴파일러는 그것을 평가하는 동안 x + a의 값을 포함하기 위해 임시 T를 만들어야합니다. 그런 다음 x에 할당 할 수 있습니다. (이 작업 중에는 x 또는 a를 작업 공간으로 사용할 수 없습니다.)

x + = a의 경우 임시가 필요하지 않습니다.

사소한 유형의 경우 차이가 없습니다.


8

의 차이 x = x + a와는 x += a기계가 통과하는 일의 양입니다 - 어떤 컴파일러는 (일반적으로 할) 수 멀리 최적화,하지만 우리는 잠시 동안 최적화를 무시하면 일반적으로, 무슨 일 것은 그 이전의 코드에서, 머신은 값을 x두 번 조회해야하지만 후자의 경우이 조회는 한 번만 발생하면됩니다.

그러나 내가 언급했듯이 오늘날 대부분의 컴파일러는 명령을 분석하고 필요한 기계 명령을 줄일 수있을만큼 지능적입니다.

추신 : Stack Overflow에 대한 첫 번째 답변!


6

이 C ++에 레이블을 지정 했으므로 게시 한 두 가지 진술에서 알 수있는 방법이 없습니다. 'x'가 무엇인지 알아야합니다 (답변 '42'와 약간 비슷합니다). xPOD 라면 실제로 큰 차이를 만들지 않을 것입니다. 그러나 x클래스 인 경우 실행 시간이 매우 다른 다른 동작을 가질 수 있는 operator +operator +=메서드에 대한 오버로드가있을 수 있습니다 .


6

+=컴파일러의 삶을 훨씬 더 쉽게 만들고 있다고 말한다면 . 컴파일러 x = x+a가 이것이와 동일한 것을 인식 x += a하려면 컴파일러는

  • 왼쪽 ( x)을 분석하여 부작용이없고 항상 동일한 l- 값을 참조하는지 확인합니다. 예를 들어, 일 수 있으며 z[i]둘 다 zi변경되지 않도록해야합니다 .

  • 오른쪽 ( x+a)을 분석하고 합계인지 확인하고에서와 같이 변환 할 수 있더라도 왼쪽이 오른쪽에서 한 번만 발생하는지 확인합니다 z[i] = a + *(z+2*0+i).

당신이 의미하는 것이에 추가 a하는 것이라면 x컴파일러 작성자는 당신이 의미하는 바를 말할 때 그것을 고맙게 생각합니다. 그렇게하면 작성자 가 모든 버그를 제거 하기를 바라는 컴파일러의 일부 를 사용하지 않고 솔직히 머리를 뺄 수없는 경우 가 아니라면 실제로 삶을 더 쉽게 만들 수 없습니다. 포트란 모드의.


5

구체적인 예를 들어 간단한 복소수 유형을 상상해보십시오.

struct complex {
    double x, y;
    complex(double _x, double _y) : x(_x), y(_y) { }
    complex& operator +=(const complex& b) {
        x += b.x;
        y += b.y;
        return *this;
    }
    complex operator +(const complex& b) {
        complex result(x+b.x, y+b.y);
        return result;
    }
    /* trivial assignment operator */
}

a = a + b의 경우 추가 임시 변수를 만든 다음 복사해야합니다.


이것은 매우 좋은 예입니다. 두 연산자가 어떻게 구현되었는지 보여줍니다.
Grijesh Chauhan 2013-08-07

5

당신은 잘못된 질문을하고 있습니다.

이로 인해 앱이나 기능의 성능이 향상되지는 않습니다. 그랬더라도 알아내는 방법 은 코드 를 프로파일 링 하고 그것이 당신에게 어떤 영향을 미치는지 확실히 아는 것입니다. 이 수준에서 어느 것이 더 빠른지 걱정하는 대신 명확성, 정확성 및 가독성 측면에서 생각하는 것이 훨씬 더 중요 합니다.

이것은 중요한 성능 요소이더라도 컴파일러는 시간이 지남에 따라 진화한다는 것을 고려할 때 특히 그렇습니다. 누군가가 새로운 최적화를 알아 내고 오늘의 정답이 내일 잘못 될 수 있습니다. 조기 최적화의 전형적인 경우입니다.

이것은 성능이 전혀 중요하지 않다는 말이 아닙니다. 단지 성능 목표를 달성하기위한 잘못된 접근 방식이라는 것입니다. 올바른 접근 방식은 프로파일 링 도구를 사용하여 코드가 실제로 시간을 소비하는 위치와 노력을 집중할 위치를 파악하는 것입니다.


물론이다. 그러나 그것은 "언제 그런 차이를 고려해야 하는가"라는 큰 그림이 아니라 낮은 수준의 질문이었다.
Chiffa 2013 년

1
OP의 질문은 다른 사람의 답변 (및 찬성 투표)에서 알 수 있듯이 완전히 합법적이었습니다. 우리는 당신의 포인트를 얻을 수 있지만 (첫 번째 프로필을, 등)은 확실히 이다 이런 종류의 물건을 알고 흥미 - 당신은 정말 당신이 먹는 각 결정의 결과를 프로파일, 당신이 쓰는 각각의 모든 사소한 문을 프로파일 링하는 건가요? 이미 케이스를 연구하고, 프로파일 링하고, 분해하고, 일반적인 답변을 제공 한 사람들이 SO에있는 경우에도?

4

기계와 아키텍처에 따라 달라져야한다고 생각합니다. 아키텍처가 간접 메모리 주소 지정을 허용하는 경우 컴파일러 작성자는 최적화를 위해이 코드를 대신 사용할 수 있습니다.

mov $[y],$ACC

iadd $ACC, $[i] ; i += y. WHICH MIGHT ALSO STORE IT INTO "i"

반면 i = i + y에 (최적화없이) 번역 될 수 있습니다.

mov $[i],$ACC

mov $[y],$B 

iadd $ACC,$B

mov $B,[i]


즉, if i가 포인터를 반환하는 함수 등의 다른 문제 도 고려해야합니다. GCC를 포함한 대부분의 프로덕션 수준 컴파일러는 두 문에 대해 동일한 코드를 생성합니다 (정수인 경우).


2

아니요, 두 가지 방법 모두 동일하게 처리됩니다.


10
오버로드 된 연산자가있는 사용자 정의 형식이면 아닙니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.