문제

사이에 성능 차이가 있습니까? i++ 그리고 ++i 결과 값이 사용되지 않으면?

도움이 되었습니까?

해결책

임원 요약 : 아니요.

i++++i의 이전 값이 있기 때문에 i보다 느릴 수 있습니다. 나중에 사용하기 위해 저장해야 할 수도 있지만 실제로는 모든 최신 컴파일러는이를 최적화합니다.

이 함수의 코드를 살펴보면이를 입증 할 수 있습니다. ++ii++를 모두 사용합니다. 라코 디스

++ii++를 제외하고 파일은 동일합니다. 라코 디스

우리는 그것들을 컴파일하고 생성 된 어셈블러도 얻을 것입니다 : 라코 디스

생성 된 객체와 어셈블러 파일이 모두 동일하다는 것을 알 수 있습니다. 라코 디스

다른 팁

효율성 대 의도 : Andrew Koenig : <인용구>

첫째, 최소한 정수 변수와 관련하여 ++ii++보다 더 효율적이라는 것은 분명하지 않습니다.

및 : <인용구>

따라서 질문해야 할 질문은이 두 작업 중 어느 것이 더 빠른지가 아니라,이 두 작업 중 어느 것이 수행하려는 작업을 더 정확하게 표현하는지입니다. 나는 표현의 값을 사용하지 않는다면, i++ 대신 ++i를 사용할 이유가 없다고 제출합니다. 왜냐하면 변수의 값을 복사하고 변수를 증가시킨 다음 복사본을 버릴 이유가 없기 때문입니다. .

따라서 결과 값이 사용되지 않으면 ++i를 사용합니다. 하지만 더 효율적이기 때문이 아닙니다. 내 의도를 정확하게 설명하기 때문입니다.

더 나은 대답은 ++i가 때때로 더 빠르지 만 결코 느리지 않을 것이라는 것입니다.

모두가 iint와 같은 일반적인 내장 유형이라고 가정하는 것 같습니다. 이 경우 측정 가능한 차이는 없습니다.

그러나 i가 복잡한 유형이라면 측정 가능한 차이를 찾을 수 있습니다. i++의 경우 클래스를 증가시키기 전에 클래스의 복사본을 만들어야합니다. 복사에 포함 된 내용에 따라 ++it를 사용하면 최종 값을 반환 할 수 있기 때문에 실제로 느려질 수 있습니다. 라코 디스

또 다른 차이점은 ++i를 사용하면 값 대신 참조를 반환하는 옵션이 있다는 것입니다. 다시 말하지만, 개체의 복사본을 만드는 데 관련된 사항에 따라 속도가 느려질 수 있습니다.

이러한 상황이 발생할 수있는 실제 사례는 반복기 사용입니다. 반복기를 복사하는 것이 애플리케이션의 병목 현상이 아닐 가능성은 있지만 결과에 영향을 미치지 않는 경우 ++i 대신 i++를 사용하는 습관을들이는 것이 좋습니다.

Scott Meyers의 잎사귀, 더 효과적인 C ++ 항목6 : 증가 및 감소 연산의 접두사 및 접미사 형태를 구분합니다 .

객체, 특히 반복자의 경우 접두사 버전이 항상 접미사보다 선호됩니다.

통신사의 통화 패턴을 살펴보면 그 이유입니다. 라코 디스

이 예를 보면 접두사 연산자가 접미사보다 항상 더 효율적이라는 것을 쉽게 알 수 있습니다.접미사를 사용할 때 임시 개체가 필요하기 때문입니다.

이것이 반복자를 사용하는 예를 볼 때 항상 접두사 버전을 사용하는 이유입니다.

하지만 int에 대해 지적했듯이 컴파일러 최적화가 발생할 수 있기 때문에 사실상 차이가 없습니다.

미시적 최적화가 걱정되는 경우 추가 관찰이 있습니다.감소 루프는 다음과 같은 경우 증가 루프보다 '가능하면'더 효율적일 수 있습니다 (명령어 세트 아키텍처에 따라 다름). 라코 디스

각 루프마다 다음 항목에 대한 지침이 하나씩 있습니다.

  1. 1i 추가.
  2. i100보다 작은 지 비교합니다.
  3. i100보다 작은 경우 조건부 분기

    감소 루프 : 라코 디스

    루프에는 다음에 대한 지침이 있습니다.

    1. i를 줄이고 CPU 레지스터 상태 플래그를 설정합니다.
    2. CPU 레지스터 상태에 따른 조건부 분기 (Z==0)

      물론 이것은 0으로 감소 할 때만 작동합니다!

      ARM 시스템 개발자 가이드에서 기억합니다.

짧은 답변:

사이에는 결코 차이가 없습니다. i++ 그리고 ++i 속도면에서.좋은 컴파일러는 두 경우에 서로 다른 코드를 생성해서는 안 됩니다.

긴 답변:

다른 모든 답변에서 언급하지 못한 것은 ++i ~ 대 i++ 발견된 표현 내에서만 의미가 있습니다.

의 경우 for(i=0; i<n; i++), i++ 그 자체의 표현은 다음과 같습니다.앞에 시퀀스 포인트가 있습니다. i++ 그리고 그 뒤에 하나가 있습니다.따라서 생성된 유일한 기계어 코드는 "증가"입니다. i ~에 의해 1" 그리고 이것이 프로그램의 나머지 부분과 관련하여 어떻게 순서가 지정되는지는 잘 정의되어 있습니다.따라서 접두사로 변경하려면 ++, 그것은 전혀 중요하지 않습니다. 여전히 기계 코드 "increase"를 얻을 것입니다. i ~에 의해 1".

차이점 ++i 그리고 i++ 다음과 같은 표현에서만 중요합니다. array[i++] = x; ~ 대 array[++i] = x;.어떤 사람들은 그런 작업에서 접미사가 더 느려질 것이라고 주장하고 말할 수도 있습니다. i 상주 파일은 나중에 다시 로드해야 합니다.그러나 C 표준에서 부르는 것처럼 "추상 기계의 동작을 중단"하지 않는 한 컴파일러는 원하는 방식으로 명령을 자유롭게 주문할 수 있습니다.

그래서 당신이 그렇게 생각할 수도 있지만 array[i++] = x; 다음과 같이 기계어 코드로 번역됩니다.

  • 저장 가치 i A 레지스터에
  • 레지스터 B에 배열의 주소를 저장합니다.
  • A와 B를 더하고 결과를 A에 저장합니다.
  • A로 표시되는 이 새 주소에 x 값을 저장합니다.
  • 저장 가치 i 레지스터 A // 여기에 추가 명령이 있기 때문에 비효율적입니다. 우리는 이미 이 작업을 한 번 수행했습니다.
  • 증분 레지스터 A.
  • 레지스터 A를 다음 위치에 저장 i.

컴파일러는 다음과 같이 코드를 보다 효율적으로 생성할 수도 있습니다.

  • 저장 가치 i A 레지스터에
  • 레지스터 B에 배열의 주소를 저장합니다.
  • A와 B를 더하고 결과를 B에 저장합니다.
  • 증분 레지스터 A.
  • 레지스터 A를 다음 위치에 저장 i.
  • ...// 나머지 코드.

C 프로그래머로서 당신이 접미사라고 생각하도록 교육을 받았기 때문입니다. ++ 마지막에 발생하면 기계어 코드를 그런 식으로 주문할 필요가 없습니다.

따라서 접두사와 접미사의 차이는 없습니다. ++ C에서이제 C 프로그래머로서 당신이 변해야 할 것은 이유 없이 어떤 경우에는 접두어를 사용하고 다른 경우에는 접미어를 일관되지 않게 사용하는 사람들입니다.이는 C가 어떻게 작동하는지 확신하지 못하거나 언어에 대한 잘못된 지식을 갖고 있음을 의미합니다.이것은 항상 나쁜 징조이며, 이는 그들이 미신이나 "종교적 교리"에 기초하여 프로그램에서 다른 의심스러운 결정을 내리고 있음을 암시합니다.

"접두사 ++ 항상 더 빠르다"라는 말은 실제로 C 프로그래머가 되려는 사람들 사이에서 흔히 볼 수 있는 잘못된 교리 중 하나입니다.

'어떤 것이 더 빠른지'라는 질문이 어느 것을 사용할지 결정하는 요소가되지 않도록하십시오.그다지 신경 쓰지 않을 가능성이 높으며 프로그래머가 읽는 시간이 기계 시간보다 훨씬 비쌉니다.

코드를 읽는 사람에게 가장 의미있는 것을 사용하세요.

가장 먼저:차이점은 다음과 같습니다. i++ 그리고 ++i C에서는 무시할 수 있습니다.


세부 사항.

1.잘 알려진 C++ 문제: ++i 가 더 빠르다

C++에서는 ++i iff가 더 효율적입니다. i 오버로드된 증분 연산자가 있는 일종의 객체입니다.

왜?
~ 안에 ++i, 객체는 먼저 증가되고 이후에 다른 함수에 대한 const 참조로 전달될 수 있습니다.표현이 다음과 같은 경우에는 불가능합니다. foo(i++) 왜냐하면 이제 증분은 이전에 수행되어야 하기 때문입니다. foo() 호출되지만 이전 값을 전달해야 합니다. foo().결과적으로 컴파일러는 강제로 복사본을 만들어야 합니다. i 원본에 대해 증분 연산자를 실행하기 전에.추가 생성자/소멸자 호출은 나쁜 부분입니다.

위에서 언급했듯이 이는 기본 유형에는 적용되지 않습니다.

2.잘 알려지지 않은 사실: i++ 5월 더 빨라지다

생성자/소멸자를 호출할 필요가 없는 경우(C에서는 항상 그렇습니다) ++i 그리고 i++ 똑같이 빨라야겠죠?아니요.거의 동일하게 빠르지만 작은 차이가 있을 수 있으며 대부분의 다른 답변자는 잘못된 방법을 사용합니다.

어떻게 i++ 더 빨라질까?
요점은 데이터 종속성입니다.값을 메모리에서 로드해야 하는 경우 값을 증가시키고 사용하는 두 가지 후속 작업을 수행해야 합니다.와 함께 ++i, 증분을 수행해야합니다 ~ 전에 값을 사용할 수 있습니다.와 함께 i++, 사용은 증분에 의존하지 않으며 CPU는 사용 작업을 수행할 수 있습니다. 병행하여 증분 연산에 들어갑니다.차이점은 최대 1개의 CPU 사이클이므로 실제로는 무시할 수 있지만 존재합니다.그리고 그것은 많은 사람들이 기대하는 것과는 정반대입니다.

@ 마크 컴파일러가 변수의 (스택 기반) 임시 복사본을 최적화 할 수 있고 gcc (최신 버전에서)가 그렇게하더라도 모든 컴파일러가 항상 그렇게 할 것이라는 의미는 아닙니다.

현재 프로젝트에서 사용하는 컴파일러로 방금 테스트했으며 4 개 중 3 개는 최적화하지 않았습니다.

컴파일러가 올바르게 작동한다고 가정하지 마십시오. 특히 더 빠르지 만 결코 느린 코드가 읽기 쉬운 경우에는 더욱 그렇습니다.

코드에서 연산자 중 하나를 정말 바보로 구현하지 않은 경우 :

Alwas는 i ++보다 ++ i를 선호했습니다.

C에서 컴파일러는 일반적으로 결과가 사용되지 않는 경우 동일하게 최적화 할 수 있습니다.

그러나 C ++에서 자체 ++ 연산자를 제공하는 다른 유형을 사용하는 경우 접두사 버전이 접미사 버전보다 빠를 가능성이 있습니다.따라서 접미사 의미가 필요하지 않은 경우 접두사 연산자를 사용하는 것이 좋습니다.

접두사가 접두사 증가보다 느린 상황을 생각할 수 있습니다.

레지스터 A가있는 프로세서가 누산기로 사용되고 많은 명령에서 사용되는 유일한 레지스터라고 상상해보십시오 (일부 소형 마이크로 컨트롤러는 실제로 이와 같습니다).

이제 다음 프로그램과 가상 어셈블리로의 번역을 상상해보십시오.

접두사 증가 : 라코 디스

후위 증분 : 라코 디스

b의 값이 어떻게 강제로 다시로드되었는지 확인하세요. 접두사 증분을 사용하면 컴파일러는 값을 증분하고 계속 사용할 수 있습니다. 원하는 값이 증분 후에 이미 레지스터에 있으므로 다시로드하지 않아도됩니다. 그러나 접미사 증분을 사용하면 컴파일러는 이전 값과 증분 값의 두 값을 처리해야합니다.이 값은 위에서 보여 주듯이 한 번 더 메모리 액세스를 발생시킵니다.

물론 단일 i++; 문과 같이 증분 값이 사용되지 않는 경우 컴파일러는 접미사 또는 접두사 사용에 관계없이 단순히 증분 명령어를 생성 할 수 있습니다. <시간>

부수적으로 말씀 드리고 싶은 것은 유전자 라 코디 세 태그 코드가있는 표현은 추가적인 노력없이 (예를 들어 유전자 라코 디스 태그 코드를 추가함으로써) 단순히 유전자 라 코디 세 태그 코드가있는 것으로 변환 될 수 없다는 것입니다. 따라서 두 표현이 일부 표현의 일부인 경우 비교하는 것은 실제로 유효하지 않습니다. 종종 표현 안에 b++를 사용하는 경우 ++b를 사용할 수 없으므로 - 1가 잠재적으로 더 효율적이더라도 단순히 잘못되었을 것입니다. 물론 표현식이 구걸하는 경우는 예외입니다 (예 : b++로 변경할 수있는 ++b).

항상 사전 증가를 선호하지만 ...

연산자 ++ 함수를 호출하는 경우에도 컴파일러는 함수가 인라인되면 임시를 최적화 할 수 있다는 점을 지적하고 싶었습니다.operator ++는 일반적으로 짧고 종종 헤더에 구현되기 때문에 인라인 될 가능성이 높습니다.

실제적으로 두 형식의 성능에는 큰 차이가 없을 것입니다.그러나 저는 항상 사전 증분을 선호합니다. 최적화 프로그램에 의존하여 파악하는 것보다 제가 말하려는 내용을 직접 표현하는 것이 더 낫기 때문입니다.

또한 옵티마이 저가 수행 할 작업을 줄이면 컴파일러가 더 빠르게 실행됩니다.

C가 약간 녹슬 어서 미리 사과드립니다.Speedwise, 결과를 이해할 수 있습니다.그러나 두 파일이 동일한 MD5 해시로 어떻게 나왔는지 혼란 스럽습니다.for 루프는 동일하게 실행되지만 다음 두 줄의 코드가 다른 어셈블리를 생성하지 않을까요? 라코 디스

라코 디스

첫 번째는 배열에 값을 쓴 다음 i를 증가시킵니다.두 번째 증분 i는 배열에 씁니다.저는 어셈블리 전문가는 아니지만이 두 줄의 코드로 동일한 실행 파일이 어떻게 생성되는지 알 수 없습니다.

단지 2 센트

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top