C에서 i ++와 ++ i 사이에 성능 차이가 있습니까?


답변:


396

행정상 개요 : 아니다.

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

우리는이 기능의 코드를 보면이 설명과 함께 모두 수 ++ii++.

$ cat i++.c
extern void g(int i);
void f()
{
    int i;

    for (i = 0; i < 100; i++)
        g(i);

}

파일은 제외하고, 동일 ++ii++:

$ diff i++.c ++i.c
6c6
<     for (i = 0; i < 100; i++)
---
>     for (i = 0; i < 100; ++i)

컴파일하고 생성 된 어셈블러를 얻습니다.

$ gcc -c i++.c ++i.c
$ gcc -S i++.c ++i.c

그리고 생성 된 객체와 어셈블러 파일이 동일하다는 것을 알 수 있습니다.

$ md5 i++.s ++i.s
MD5 (i++.s) = 90f620dda862cd0205cd5db1f2c8c06e
MD5 (++i.s) = 90f620dda862cd0205cd5db1f2c8c06e

$ md5 *.o
MD5 (++i.o) = dd3ef1408d3a9e4287facccec53f7d22
MD5 (i++.o) = dd3ef1408d3a9e4287facccec53f7d22

9
나는이 질문이 C에 관한 것이라는 것을 알고 있지만 브라우저가 자바 스크립트에 대해이 최적화를 수행 할 수 있는지 알고 싶습니다.
TM.

69
따라서 "아니오"는 테스트 한 하나의 컴파일러에 해당됩니다.
Andreas

173
@Andreas : 좋은 질문입니다. 필자는 컴파일러 작성자였으며 많은 CPU, 운영 체제 및 컴파일러에서이 코드를 테스트 할 수있었습니다. i ++ 사례를 최적화하지 않은 유일한 컴파일러 (실제로 전문가의 관심을 끌었던 컴파일러)는 Walt Bilofsky의 Software Toolworks C80 컴파일러였습니다. 그 컴파일러는 인텔 8080 CP / M 시스템 용이었습니다. 이 최적화를 포함하지 않은 컴파일러는 일반적인 용도를위한 것이 아니라고 말하는 것이 안전합니다.
마크 해리슨

22
성능 차이가 무시할 만하고 많은 경우에 최적화되어 있지만 사용하는 것이 좋습니다. ++i 대신 대신 것이 좋습니다 i++. 하지 말아야 할 이유가 전혀 없으며, 소프트웨어가 툴체인을 통해 최적화하지 않는 소프트웨어를 통과하면 소프트웨어가 더 효율적입니다. 이를 감안하면 그냥 쉽게 입력 할 수 있습니다 ++i가 입력이기 때문에 i++, 사용하지에 대한 변명 정말 없다 ++i처음에이.
monokrome

7
@monokrome 개발자가 많은 언어로 접두사와 접미사 연산자를 구현할 수 있기 때문에 컴파일러가 이러한 함수를 먼저 비교하지 않고 만들 수있는 적절한 솔루션이 아닐 수도 있습니다.
pickypg

112

에서 의도 대비 효율성 앤드류 코에 닉의 :

첫째, 적어도 정수 변수가 관련된 경우 ++i보다 더 효율적인 것은 분명하지 i++않습니다.

그리고 :

따라서 두 가지 작업 중 어느 것이 더 빠르지 않은지, 두 가지 작업 중 어떤 것이 달성하려는 것을 더 정확하게 표현하는지에 대한 질문이 있습니다. 변수 값을 복사하고 변수를 증가시킨 다음 복사본을 버릴 이유가 없기 때문에 표현식 값을 사용하지 않는 경우 i++대신 대신 사용할 이유 ++i가 없다고 제출합니다.

따라서 결과 값을 사용하지 않으면을 사용합니다 ++i. 그러나 그것이 더 효율적이기 때문에가 아닙니다 : 그것은 내 의도를 올바르게 진술하기 때문입니다.


5
다른 단항 연산자도 접두사라는 것을 잊지 마십시오. 나는 ++ i가 단항 연산자를 사용하는 "의미론적인"방법이라고 생각하지만, i ++는 특정 요구 (추가 전 평가)를 맞추기 위해 준비되어 있습니다.
TM.

9
결과 값이 사용되지 않으면 의미에 차이 가 없습니다. 즉, 하나 또는 다른 구성을 선호 할 근거가 없습니다.
Eamon Nerbonne

3
독자로서 저는 차이가 있습니다. 작가로서, 나는 다른 것을 선택함으로써 나의 의도를 보여줄 것이다. 코드를 통해 프로그래머 친구 및 팀원들과 의사 소통을하는 것은 습관입니다.
Sébastien RoccaSerra

11
코닉의 조언에 따라, 나는 코드 i++같은 방법으로 내가 코드 거라고 i += n또는 i = i + n양식에, 즉, 목표 동사 객체 으로, 대상 피연산자하여 왼쪽에 동사 연산자. 의 경우 i++올바른 객체 가 없지만 동사 연산자 의 왼쪽에 대상 을 유지하면서 규칙이 계속 적용됩니다 .
David R Tribble

4
i를 늘리려 고하면 i ++와 ++ i가 모두 의도를 올바르게 표현합니다. 다른 것을 선호 할 이유가 없습니다. 독자로서 나는 아무런 차이가 없다고 생각한다. 동료들이 i ++를보고 생각할 때 혼란스러워 하는가? 어쩌면 이것은 오타 일 수도 있고 i를 증가시킬 의도는 아니었을 까?
dan carter

46

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

모두가 그것을 가정하고있는 것 같습니다 i 가 같은 기본 제공 유형int . 이 경우 측정 가능한 차이가 없습니다.

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

Foo Foo::operator++()
{
  Foo oldFoo = *this; // copy existing value - could be slow
  // yadda yadda, do increment
  return oldFoo;
}

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

이것이 발생할 수있는 실제 예는 반복자를 사용하는 것입니다. 반복자를 복사하면 응용 프로그램에서 병목 수 없을 수도 있습니다,하지만 여전히 사용하는 습관을 좋은 습관이다 ++i대신에 i++결과가 영향을받지된다.


36
이 질문은 C ++에 대한 언급이없는 C를 명시 적으로 나타냅니다.
Dan Cristoloveanu

5
이 (아마도 오래된) 질문은 C ++이 아닌 C에 관한 것이지만 C ++에서는 클래스가 post-fix 및 pre-fix 연산자를 구현하더라도 반드시 관련이 없다는 것을 언급 할 가치가 있다고 생각합니다. 예를 들어 bar ++는 하나의 데이터 멤버를 증가시킬 수 있지만 ++ bar는 다른 데이터 멤버를 증가시킬 수 있으며,이 경우 시맨틱이 다르므로 둘 중 하나를 사용할 수있는 옵션이 없습니다.
Kevin

-1 이것은 C ++ 프로그래머에게는 좋은 조언이지만 C 태그가 붙은 질문에는 아무 것도 대답하지 않습니다. C에서는 접두사를 사용하든 접두사를 사용하든 전혀 차이가 없습니다.
Lundin

@Pacerier이 질문에는 C와 C 만 태그되어 있습니다. 왜 그들이 관심이 없다고 가정합니까? SO의 작동 방식을 고려할 때 Java, C #, COBOL 또는 기타 다른 주제가 아닌 C 에만 관심 이 있다고 가정하는 것이 현명하지 않습니까?
Lundin

18

짧은 답변:

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

긴 대답 :

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

의 경우 for(i=0; i<n; i++)는은 i++자신의 표현에 혼자 : 전과 시퀀스 포인트가 i++그것을 하나씩있다. 따라서 생성 된 유일한 기계 코드는 "증가한 i로는 1"이 프로그램의 나머지 부분과 관련하여 염기 서열을 얼마나 잘 정의되어있다. 그래서 당신은 접두사로 변경한다면 ++, 그것은 문제가 조금, 당신은 여전히 머신 코드 "증가 얻을 것없는 것 i에 의해를 1".

사이의 차이 ++ii++같은 표현 만 문제 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 프로그래머로서 postfix ++가 마지막에 발생 한다고 생각하도록 훈련을 받았다고 해서 기계 코드를 그런 식으로 주문할 필요는 없습니다.

따라서 ++C 에서는 접두사와 접미사 사이에 차이가 없습니다 . 이제 C 프로그래머는 다양해야합니다. 이유에 관계없이 접두사를 일관성없이 사용하고 어떤 경우에는 접두사를 사용하는 사람들이 있습니다. 이는 C의 작동 방식에 대해 확신이 없거나 언어에 대한 지식이 잘못되었음을 나타냅니다. 이것은 항상 나쁜 징조이며, 결과적으로 그들이 미신이나 "종교적 교리"에 근거하여 프로그램에서 다른 의심스러운 결정을 내린다고 제안합니다.

"접두사 ++가 항상 빠릅니다"는 C 프로그래머들 사이에서 흔히 볼 수있는 잘못된 교리 중 하나입니다.


3
"접두사 ++가 항상 빠릅니다"라고 말한 사람은 없습니다. 잘못 인용되었습니다. 그들이 말한 것은 "Postfix ++는 결코 빠르지 않다 "입니다.
Pacerier

2
@Pacerier 나는 특정한 사람을 인용하는 것이 아니라 널리 퍼져있는 잘못된 믿음을 인용합니다.
Lundin

@rbaleksandar C ++! = C.
Lundin

@rbaleksandar 질문과 답변 모두 C ++에 대해 이야기합니다. 연산자 오버로딩 및 복사 생성자 등이 있으므로 C와 다릅니다.
Lundin

3
@rbaleksandar c ++ == c && ++ c! = c
sadljkfhalskdjfh

17

Scott Meyers에서 보다 효과적인 c ++ 항목 6 : 접두사와 접미사 형태의 증분 및 감소 연산 구분 .

접두사 버전은 객체, 특히 반복자와 관련하여 항상 접미사보다 우선합니다.

연산자의 호출 패턴을 보면이 이유가 있습니다.

// Prefix
Integer& Integer::operator++()
{
    *this += 1;
    return *this;
}

// Postfix
const Integer Integer::operator++(int)
{
    Integer oldValue = *this;
    ++(*this);
    return oldValue;
}

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

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

그러나 int가 지적한 것처럼 컴파일러 최적화로 인해 실제로 차이가 없습니다.


4
나는 그의 질문이 C에 관한 것이라고 생각하지만 C ++의 경우 절대적으로 맞으며 C 사람들은 C ++에서도 사용할 수 있으므로 이것을 채택해야합니다. 나는 너무 자주 C 프로그래머가 접미사 구문을 사용하는 것을 본다 ;-)
Anders Rune Jensen

-1 이것은 C ++ 프로그래머에게는 좋은 조언이지만 C 태그가 붙은 질문에는 아무 것도 대답하지 않습니다. C에서는 접두사를 사용하든 접두사를 사용하든 전혀 차이가 없습니다.
Lundin

1
@Lundin 접두사와 postifx는 Andreas 의 답변에 따라 C에서 중요 합니다. 당신은 컴파일러가 최적화 할 것이라고 가정 할 수 없으며 어떤 언어 단지 좋습니다 ++ 난을 통해 ++ 내가 선호 Alwas
JProgrammer

@JProgrammer 그들은 당신의 답변에 따라 진심으로 중요하지 않습니다 :) 다른 코드를 생성하는 것을 발견하면 최적화를 활성화하지 못했거나 컴파일러가 잘못 되었기 때문입니다. 어쨌든, 귀하의 답변은 C에 관한
것이기

16

마이크로 최적화가 걱정되는 경우 추가 관찰 사항이 있습니다. 다음과 같은 경우 감소 루프는 증가하는 루프 (명령 세트 아키텍처에 따라 ARM과 같은) 증가 루프보다 '효율적'일 수 있습니다.

for (i = 0; i < 100; i++)

각 루프마다 다음에 대한 명령이 하나씩 있습니다.

  1. 추가 1i.
  2. i보다 작은 지 비교하십시오 100.
  3. 조건 분기는 경우 i보다는 더 적은이다 100.

감소 루프 반면 :

for (i = 100; i != 0; i--)

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

  1. 감소 i, CPU 레지스터 상태 플래그 설정
  2. CPU 레지스터 상태 ( Z==0) 에 따른 조건부 분기 입니다.

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

ARM 시스템 개발자 안내서에서 기억합니다.


좋아요 그러나 이것이 캐시 적중 횟수를 줄이지 않습니까?
AndreasT

코드 최적화 서적에서 오래된 이상한 트릭이 있습니다 .0 테스트 분기의 이점과 증가 된 주소가 결합되었습니다. 다음은 고급 언어의 예입니다 (많은 컴파일러가 효율적이지만 더 일반적인 루프 코드 로 대체 할만큼 똑똑하기 때문에 아마도 쓸모가 없습니다 ) : int a [N]; for (i = -N; i; ++ i) a [N + i] + = 123;
noop

@noop 당신은 당신이 참조하는 코드 최적화 서적을 자세히 설명 할 수 있습니까? 나는 좋은 것을 찾기 위해 고군분투했다.
mezamorphic

7
이 답변은 질문에 대한 답변이 아닙니다.
monokrome

@mezamorphic x86의 소스는 Intel 최적화 매뉴얼, Agner Fog, Paul Hsieh, Michael Abrash입니다.
noop

11

"어느 쪽이 빠를까"라는 질문이 어떤 결정을 내릴 것인지 결정하지 마십시오. 그다지 신경 쓰지 않을 것입니다. 게다가 프로그래머의 읽기 시간이 기계 시간보다 훨씬 비쌉니다.

사람이 코드를 읽는 데 가장 적합한 것을 사용하십시오.


3
실제 효율성 향상과 전반적인 의도의 명확성에 대한 모호한 가독성 개선을 선호하는 것은 잘못이라고 생각합니다.
noop

4
"프로그래머 읽기 시간"이라는 용어는 "의도의 명확성"과 대략 유사합니다. "실제 효율성 향상"은 종종 측정 할 수 없으며 0에 가깝게 0에 가깝습니다. OP의 경우, ++ i가 병목 현상임을 발견하기 위해 코드를 프로파일 링하지 않는 한, 어느 것이 더 빠른지에 대한 문제는 시간 낭비와 프로그래머 사고 단위입니다.
앤디 레스터

2
++ i와 i ++의 가독성의 차이는 개인 취향의 문제 일 뿐이지 만, ++ i는 컴파일러 최적화 관련 사소한 경우와 간단한 데이터 유형과 동등한 결과에도 불구하고 i ++보다 간단한 작동을 분명히 나타냅니다. 따라서 ++ i는 증가 후의 특정 속성이 필요하지 않은 경우 나에게 승자입니다.
noop

당신은 내가 말하는 것을 말하고 있습니다. "효율성"에 대해 걱정하는 것보다 의도를 보이고 가독성을 향상시키는 것이 더 중요합니다.
Andy Lester

2
여전히 동의 할 수 없습니다. 우선 순위 목록에서 가독성이 높은 경우 프로그래밍 언어 선택이 잘못되었을 수 있습니다. C / C ++의 주요 목적은 효율적인 코드를 작성하는 것입니다.
noop

11

우선 : C의 차이점 i++++iC에서는 무시할 수 있습니다.


세부 사항에.

1. 잘 알려진 C ++ 문제 : ++i더 빠름

C ++에서는 ++i오버플 i로 증분 연산자가있는 일종의 객체입니다.

왜?
에서는 ++i, 물체를 먼저 증가시키고,이어서 임의의 다른 함수에 CONST 기준으로 통과 할 수있다. 표현식 이 호출 foo(i++)되기 전에 증분을 수행해야 foo()하지만 이전 값을 전달해야하기 때문에 표현식이 가능한 경우에는 불가능합니다.foo() . 결과적으로 컴파일러는 i원본에서 증가 연산자를 실행하기 전에 사본을 작성 해야합니다. 추가적인 생성자 / 소멸자 호출은 나쁜 부분입니다.

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

2. 작은 사실 : i++ may 더 빠를 있습니다

생성자 / 소멸자 C의 경우는 항상, 어떤 호출 할 필요가 없을 경우 ++ii++ 오른쪽 똑같이 빠른해야 하는가? 아닙니다. 거의 똑같이 빠르지 만 작은 차이가있을 수 있습니다. 대부분의 다른 응답자들은 잘못된 길을 가고 있습니다.

어떻게 i++더 빠를 수 있습니까?
요점은 데이터 의존성입니다. 메모리에서 값을로드해야하는 경우 두 개의 후속 조작을 수행하여이를 증가시키고 사용해야합니다. 을 사용 하면 값을 사용 하기 전에++i 증분을 수행 해야 합니다. 를 사용하면 i++증분에 의존하지 않고 CPU는 증분 작업 과 병행 하여 사용 작업 수행 할 수 있습니다 . 차이는 최대 하나의 CPU주기이므로 실제로 무시할 수는 있지만 실제로는 있습니다. 그리고 그것은 많은 사람들이 기대하는 다른 방법입니다.


요점 정보 2 : ++i또는 i++다른 식에서 또는를 사용하는 경우 식 사이를 변경하면 식의 의미가 변경되므로 가능한 성능 향상 / 손실은 의심의 여지가 없습니다. 그것들이 독립형이라면, 즉 연산의 결과가 즉시 사용되지 않는다면, 괜찮은 컴파일러는 그것을 동일한 것으로, 예를 들어 INC어셈블리 명령으로 컴파일 할 것 입니다.
Shahbaz

1
@Shahbaz 그것은 사실이지만, 요점은 아닙니다. 1) 의미가 다르다하더라도, 양 i++++i그들이 프로그래머가 무엇에 가까운 당량 그래서, 하나의 루프 상수를 조정함으로써 거의 모든 가능한 상황에서 상호 교환 적으로 사용될 수있다. 2) 둘 다 동일한 명령어로 컴파일하더라도 CPU마다 실행이 다릅니다. 의 경우 i++CPU는 동일한 값을 사용하는 다른 명령어 (CPU는 실제로이 작업을 수행함)와 병렬 로 증분 계산할 수 있지만 ++i, CPU는 증분 다른 명령어를 예약해야합니다 .
cmaster-monica reinstate 모니카

4
일례로서 @Shahbaz : if(++foo == 7) bar();if(foo++ == 6) bar();기능적으로 동일하다. 그러나 비교와 증분은 CPU에 의해 병렬로 계산 될 수 있기 때문에 두 번째는 한 사이클 더 빠를 수 있습니다. 이 단일 사이클이 중요하지는 않지만 차이점이 있습니다.
cmaster-monica reinstate 모니카

1
좋은 지적. 상수 는 일반적으로 사용되는 위치 ( <예 : vs <=) ++가 많이 나타나므로 종종 사이의 변환이 쉽게 가능합니다.
Shahbaz

1
나는 포인트 2를 좋아하지만 값이 사용되는 경우에만 적용됩니다. "결과 값을 사용하지 않으면?"이라는 질문에 혼동 될 수 있습니다.
jinawee

7

@Mark 컴파일러가 변수의 (스택 기반) 임시 복사본을 최적화하고 gcc (최근 버전)가 그렇게한다고하더라도 모든 컴파일러가 항상 그렇게하는 것은 아닙니다.

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

더 빠르지 만 느리지 않은 코드가 읽기 쉬운 경우 컴파일러가 올바르게 처리한다고 가정하지 마십시오.

코드에서 연산자 중 하나를 실제로 어리석게 구현하지 않은 경우 :

Alwas는 i ++보다 ++ i를 선호합니다.


궁금해서 ... 왜 하나의 프로젝트에서 4 개의 다른 C 컴파일러를 사용합니까? 아니면 한 팀이나 한 회사에서 그 문제에 대해?
Lawrence Dol

3
콘솔 용 게임을 만들 때 모든 플랫폼은 자체 컴파일러 / 툴체인을 제공합니다. 완벽한 세상에서는 모든 대상에 gcc / clang / llvm을 사용할 수 있지만이 세상에서는 Microsoft, Intel, Metroworks, Sony 등을 따라야합니다.
Andreas

5

C에서 컴파일러는 일반적으로 결과를 사용하지 않으면 동일하도록 최적화 할 수 있습니다.

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


4

postfix가 prefix 증가보다 느린 상황을 생각할 수 있습니다.

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

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

접두사 증가 :

a = ++b + c;

; increment b
LD    A, [&b]
INC   A
ST    A, [&b]

; add with c
ADD   A, [&c]

; store in a
ST    A, [&a]

접미사 증가 :

a = b++ + c;

; load b
LD    A, [&b]

; add with c
ADD   A, [&c]

; store in a
ST    A, [&a]

; increment b
LD    A, [&b]
INC   A
ST    A, [&b]

의 값을 b다시로드 하는 방법에 유의하십시오 . 접두사 증분을 사용하면 컴파일러는 값을 증분하고 계속 사용할 수 있습니다. 증분 후 원하는 값이 이미 레지스터에 있으므로 재로드를 피할 수 있습니다. 그러나 postfix 증가로 컴파일러는 두 가지 값을 처리해야합니다. 하나는 이전 값이고 다른 하나는 증가 된 값입니다. 위에 표시된 것처럼 하나 이상의 메모리 액세스가 발생합니다.

물론 단일 i++;명령문 과 같이 증분 값을 사용하지 않으면 컴파일러는 접미사 또는 접두사 사용법에 관계없이 증분 명령을 생성 할 수 있습니다.


부수적으로, 나는 노력 b++++b없다면 (예를 들어을 추가하여 - 1) 단순히 표현으로 변환 할 수 없다는 언급을하고 싶습니다 . 따라서 두 표현이 표현의 일부인 경우 비교하는 것은 실제로 유효하지 않습니다. 종종 b++표현식 안에서 사용 하는 곳에서는을 사용할 수 없으므로 잠재적으로 더 효율적 ++b이더라도 ++b잘못되었을 수 있습니다. 물론식이 구걸하는 경우는 예외입니다 (예 : a = b++ + 1;로 변경 가능 a = ++b;).


4

여기 답변의 대부분 의견의 대부분을 읽고 있고, 나는 모든 참조를 참조하지 않은 내가 어디 생각할 수 있다는 예를 i++보다 효율적이다 ++i(그리고 놀랍게도 --i 이었다 보다 더 효율적 i--). DEC PDP-11의 C 컴파일러를위한 것입니다!

PDP-11에는 레지스터의 사전 감소 및 사후 증가에 대한 조립 지침이 있었지만 다른 방법은 없습니다. 이 명령을 통해 "일반용"레지스터를 스택 포인터로 사용할 수 있습니다. 따라서 비슷한 *(i++)것을 사용 하면 단일 어셈블리 명령으로 컴파일 할 수는 있지만 그렇게 할 수 *(++i)는 없었습니다.

(또는 내가 말을해야 이것은 분명히 매우 비의 예이지만, 사후 증가가 더 효율적입니다 예외를 제공한다 이었다 요즘 PDP-11 C 코드에 대한 많은 수요가 아니기 때문에,).


2
매우 난해하지만 매우 흥미 롭습니다!
Mark Harrison

@daShier. +1, 나는 동의하지 않지만, 이것은 난해한 것이 아니거나 적어도 그렇게해서는 안됩니다. C는 PDP-11이 대상 프로세서였던 70 년대 초 AT & T Bell Labs에서 Unix와 공동 개발했습니다. 이 시대 포스트 증분의 유닉스 소스 코드에서 "i ++"는 개발자가 값이 "j = i ++"로 지정되거나 인덱스 "a [i ++] = n"으로 사용 된시기를 알고 있기 때문에 부분적으로 더 널리 퍼져 있습니다. 코드는 약간 더 빠를 것입니다. 사전 요구 사항이 아닌 한 포스트 증가를 사용하는 습관을들이는 것으로 보입니다. 다른 사람들은 자신의 코드를 읽고 배웠으며이 습관을 들었습니다.
jimhark

68000은 동일한 기능을 가지고 있으며, 후행 증가와 사전 감소는 하드웨어에서 지원되며 (어드레싱 모드) 다른 방식으로는 지원되지 않습니다. Motorola 팀은 음, DEC PDP-11에서 영감을 받았습니다.
jimhark

2
@jimhark, 그래, 나는 68000로 전환하고 여전히 사용하는 것이 그 PDP-11 프로그래머의 일이야 --ii++.
daShier

2

나는 항상 사전 증가를 선호합니다 ...

나는 operator ++ 함수를 호출하는 경우에도 함수가 인라인되면 컴파일러가 임시를 최적화 할 수 있다고 지적하고 싶었다. operator ++는 일반적으로 짧고 종종 헤더에서 구현되므로 인라인 될 수 있습니다.

따라서 실제적인 목적으로 두 형식의 성능에는 큰 차이가 없습니다. 그러나, 나는 항상 사전 증분을 선호합니다. 왜냐하면 내가 말하고자하는 것을 직접적으로 표현하는 것보다 직접 표현하는 것이 낫기 때문입니다.

또한 옵티마이 저의 가능성을 줄이면 컴파일러가 더 빨리 실행됩니다.


귀하의 게시는 C ++에 국한되지만 질문은 C에 관한 것입니다. 어쨌든 귀하의 답변은 잘못되었습니다 : 사용자 지정 후 증가 연산자의 경우 컴파일러는 일반적 으로 효율적인 코드를 생성 할 수 없습니다 .
Konrad Rudolph

그는 "함수가 인라인되면"이라고 말하고, 그것은 그의 추론을 옳게 만든다.
Blaisorblade

C는 연산자 오버로딩을 제공하지 않기 때문에 사전 질문과 사후 질문은 크게 흥미롭지 않습니다. 컴파일러는 기본적으로 계산되지 않은 다른 계산 된 값에 적용되는 것과 동일한 논리를 사용하여 사용하지 않는 온도를 최적화 할 수 있습니다. 샘플은 선택한 답변을 참조하십시오.

0

내 C는 조금 녹슬 었으므로 미리 사과드립니다. 결과적으로 결과를 이해할 수 있습니다. 그러나 두 파일이 동일한 MD5 해시에 어떻게 나오는지 혼란 스럽습니다. 아마도 for 루프가 동일하게 실행되지만 다음 두 줄의 코드가 다른 어셈블리를 생성하지 않습니까?

myArray[i++] = "hello";

vs

myArray[++i] = "hello";

첫 번째 값은 배열에 값을 쓴 다음 i를 증가시킵니다. 그런 다음 두 번째 증분 i는 배열에 씁니다. 나는 어셈블리 전문가가 아니지만이 두 가지 코드 줄에서 동일한 실행 파일이 어떻게 생성되는지 알지 못합니다.

내 두 센트.


1
@Jason Z 어셈블리 최적화가 완료되기 전에 컴파일러 최적화가 수행됩니다. i 변수가 같은 행의 다른 곳에서는 사용되지 않으므로 값을 유지하는 것이 낭비이므로 실제로 i ++로 뒤집습니다. 그러나 그것은 단지 추측 일뿐입니다. 강사 중 한 사람이 더 빨리 말하기를 기다릴 수 없으며 이론을 실제 증거로 수정하는 사람이됩니다. 나는 이미 적의를 거의 느낄 수있다 ^ _ ^
Tarks

3
"내 C는 조금 녹슬었기 때문에 미리 사과드립니다." C에는 아무런 문제가 없지만 원래 결과를 완전히 읽지 못했습니다. " 결과 값을 사용하지 않으면 i ++와 ++ i 사이에 성능 차이가 있습니까? "기울임 꼴을 참고하십시오. 귀하의 예에서는 i ++ / ++ i의 '결과' 사용되지만 관용적 for 루프에서는 사전 / 사후 증가 연산자의 '결과'가 사용되지 않으므로 컴파일러가 원하는 것을 수행 할 수 있습니다.
Roddy

2
귀하의 예에서 값을 사용하기 때문에 코드가 다를 수 있습니다. 동일한 예는 ++를 증분에 사용하고 둘 중 하나가 반환 한 값을 사용하지 않는 것입니다.
John Gardner

1
수정 : "컴파일러는 i ++의 반환 값이 사용되지 않으므로 ++ i로 뒤집습니다." 당신이 쓴 것도 잘못되었습니다. 왜냐하면 당신은 같은 줄에 i ++, i ++ 중 하나와 함께 i를 가질 수 없기 때문에 그 결과는 정의되지 않았습니다.
Blaisorblade

1
변경 foo[i++]foo[++i]분명히 프로그램의 의미를 변경할 것 아무 것도 변경하지 않고 있지만, 일부 프로세서 루프 게양 최적화 로직없이 컴파일러를 사용하는 경우, 증가 pq예를 들어이 수행하는 루프를 실행 한 후 한 번 *(p++)=*(q++);더 빨리하는 수행 루프를 사용하는 것보다 것을 *(++pp)=*(++q);. 일부 프로세서에서 매우 엄격한 루프의 경우 속도 차이가 클 수 있지만 (10 % 이상) 사후 증분이 사전 증분보다 훨씬 빠른 C의 경우 일 수 있습니다.
supercat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.