C : ++ i와 i ++의 차이점은 무엇입니까?


887

C에서 사용 차이 무엇인가 ++i하고 i++, 어느는 점진의 블록으로 표기 for루프?


10
원래 포스터는 관심이 없지만 C ++에서는 임시 개체를 만드는 데 사용자 정의 형식에 비용이 많이 들기 때문에 성능 차이가 클 수 있습니다.
Freund에서

답변:


1099
  • ++i의 값을 증가시킨 i다음 증가 된 값을 반환합니다.

     i = 1;
     j = ++i;
     (i is 2, j is 2)
  • i++의 값은 증가 i하지만 i증가하기 전에 유지 된 원래 값을 반환합니다 .

     i = 1;
     j = i++;
     (i is 2, j is 1)

A의 for루프 중 하나를 사용할 수 있습니다. K & R++i 에서 사용되기 때문에 더 일반적으로 보입니다 .

어떤 경우에는, "선호하는 지침을 따르 ++i통해 i++"당신은 잘못되지 않습니다.

++i및 의 효율성에 대한 몇 가지 의견이 있습니다 i++. 학생이 아닌 프로젝트 컴파일러에서는 성능 차이가 없습니다. 생성 된 코드를 보면이를 확인할 수 있으며 이는 동일합니다.

효율성 질문은 흥미 롭습니다 ... 여기에 대한 대답 은 다음과 같습니다 .C에서 i ++과 ++ i 사이에 성능 차이가 있습니까?

@OnFreund가 지적 했듯이 함수 는 C ++ 객체와 다릅니다 operator++(). 컴파일러는 중간 값을 유지하기 위해 임시 객체 생성을 최적화하는 것을 알 수 없기 때문입니다.


6
이 효과가 종료 조건에 도달했을 때 루프가 다시 한 번 실행되지 않습니까? 예를 들어, for(int i=0; i<10; i++){ print i; } 이것이 for(int i=0; i<10; ++i){ print i; } 내 이해 와 다르지 않을 것 입니다. 어떤 언어는 어떤 언어를 사용 하느냐에 따라 다른 결과를 줄 것입니다.
aVeRTRAC

27
jonnyflash는 i의 증가와 인쇄가 다른 명령문에 있기 때문에 둘 다 동일하게 작동합니다. C 스타일 ++를 지원하는 모든 언어의 경우에 해당합니다. ++ i와 i ++의 유일한 차이점은 동일한 명령문에서 연산 값을 사용할 때입니다.
마크 해리슨

16
대부분의 경우 동일한 코드를 생성 i++하기 때문에 "operand-operator-value"형식의 "operand-operator"형식이므로 선호합니다 . 다시 말해, 대상 피연산자는 대 입문에있는 것처럼 표현식의 왼쪽에 있습니다.
David R Tribble

2
@MarkHarrison, 그것은 동일하지 작동하기 때문에 것입니다 i++print i다른 문에 있지만 때문에 i++;하고 i<10있습니다. @jonnyflash의 발언은 기본이 아닙니다. 당신이 가정 for(int i=0; i++<10){ print i; }하고 for(int i=0; ++i<10){ print i; }. @johnnyflash가 첫 번째 주석에서 설명한 방식과 다르게 작동합니다.
Adam

3
@sam은 일반적인 for 루프에서 ++ i 부분에 부작용 (예 : 할당)이 없기 때문입니다.
마크 해리슨

175

나는 ++ 로 알려져 포스트 증가 하는 반면 내가 ++ 라고 사전 증가.

i++

i++i작업이 끝난 후의 값을 1 씩 증가시키기 때문에 포스트 증가 입니다.

다음 예제를 보자.

int i = 1, j;
j = i++;

의 값이 여기에 j = 1있지만 i = 2. 여기에의 값이 먼저 i할당 된 j다음 i증가합니다.

++i

++ii연산 전에 값을 1 씩 증가시키기 때문에 사전 증가 입니다. 그것은 j = i;이후에 실행될 것임을 의미 i++합니다.

다음 예제를 보자.

int i = 1, j;
j = ++i;

의 값이 여기에 j = 2있지만 i = 2. 이 값은 증분 후에 i할당됩니다 . 이전에도 마찬가지로 실행 됩니다.jii++ij=i;

for 루프의 증분 블록에서 사용해야하는 질문 은 무엇입니까? 대답은, 당신은 하나를 사용할 수 있다는 것입니다 .. 중요하지 않습니다. for 루프와 동일한 no를 실행합니다. 시간.

for(i=0; i<5; i++)
   printf("%d ",i);

for(i=0; i<5; ++i)
   printf("%d ",i);

두 루프 모두 동일한 출력을 생성합니다. 즉 0 1 2 3 4.

사용하는 곳만 중요합니다.

for(i = 0; i<5;)
    printf("%d ",++i);

이 경우 출력은입니다 1 2 3 4 5.


1
접두사 및 사후 수정 후 변수를 초기화하면 이해하는 데 도움이됩니다. 감사.
압둘 알림 샤 키르

42

어느 쪽이 더 빠른 "효율"(실제 속도)에 대해 걱정하지 마십시오. 요즘에는 이러한 것들을 처리하는 컴파일러가 있습니다. 의도를보다 명확하게 보여주는 것에 따라 사용하기에 적합한 것을 사용하십시오.


1
희망하는 바에 따르면, 사람들이 거의 사용하지 않는 (inc | dec) 이전의 이전 값이 실제로 필요하지 않은 한, 사용 된 교수 자료의 당황스러운 비율이 사용되지 않는 한 접두사 (inc | dec) rement 사용을 의미합니다. 그것이 무엇인지 알지도 못하는 후위 사용자의화물 숭배를 만드는 '..!
underscore_d

"요즘 컴파일러 ...이 일들을 돌보는 것"이 ​​보편적으로 사실인지 확실하지 않습니다. 사용자 정의 operator++(int)(접미사 버전) 내에서 코드는 거의 임시를 작성하여 반환됩니다. 컴파일러가 항상이를 최적화 할 수 있습니까?
피터-모니카 복원 복원

36

++i 값을 증가시킨 다음 반환합니다.

i++ 값을 반환 한 다음 증가시킵니다.

미묘한 차이입니다.

for 루프 ++i의 경우 약간 빠릅니다. i++그냥 버려지는 여분의 사본을 만듭니다.


23
적어도 정수에 차이를 만드는 컴파일러는 알지 못합니다.
blabla999

4
그것은이다 빠르지 . 값은 무시되고 부작용 만 유효하며 컴파일러는 정확히 동일한 코드를 생성 / 생성 할 수 있습니다.
wildplasser

31

i++:이 시나리오에서는 먼저 값이 할당 된 다음 증분이 발생합니다.

++i:이 시나리오에서는 먼저 증분이 완료된 후 값이 할당됩니다.

아래는 이미지 시각화이며, 여기 에는 동일한 것을 보여주는 멋진 실용적인 비디오 가 있습니다.

여기에 이미지 설명을 입력하십시오


어떻게 할당되지 않은 증분을 할 수 있습니까?
kouty

@kouty 변수에 할당되지 않은 레지스터를 증가시킬 수 있습니다.
Polluks

20

그 이유는 ++i 보다 약간 빠를 i++IS i++가 증가되기 전에 동안, i 값의 로컬 복사본을 요구할 수 있습니다 ++i하지 않았다. 경우에 따라 일부 컴파일러는 가능한 경우 최적화를 수행하지만 항상 가능한 것은 아니며 모든 컴파일러가이를 수행하지는 않습니다.

컴파일러 최적화에 너무 의존하지 않기 때문에 Ryan Fox의 충고를 따를 것 ++i입니다. 둘 다 사용할 수 있으면을 사용 합니다.


11
C 질문에 대한 C ++ 답변의 경우 -1입니다. i명령문을 작성할 때 값 1의 값 보다 "로컬 사본"이 더 이상 없습니다 1;.
R .. GitHub 중지 지원 얼음

14

루프 중 하나를 사용하는 효과적인 결과는 동일합니다. 다시 말해, 루프는 두 경우 모두 똑같은 일을합니다.

효율성 측면에서 ++ i보다 i ++를 선택하면 패널티가 부과 될 수 있습니다. 언어 사양 측면에서, 증가 후 연산자를 사용하면 연산자가 작동하는 값의 추가 사본을 작성해야합니다. 이것은 추가 작업의 원천이 될 수 있습니다.

그러나 앞의 논리와 관련하여 두 가지 주요 문제를 고려해야합니다.

  1. 현대 컴파일러는 훌륭합니다. 모든 우수한 컴파일러는 for-loop에서 정수 증가를보고 있음을 알기에 충분히 똑똑하며 두 방법을 동일한 효율적인 코드로 최적화합니다. 사전 증분보다 증분 후를 사용하면 실제로 프로그램 실행 시간이 느려지는 경우 끔찍한 컴파일러를 사용하는 것 입니다.

  2. 작동 시간 복잡성 측면에서 두 가지 방법 (복사가 실제로 수행되는 경우에도)은 동일합니다. 루프 내에서 수행되는 명령 수는 증분 작업의 작업 수를 크게 좌우해야합니다. 따라서 크기가 큰 루프에서는 루프 본문을 실행하여 증가 방법의 페널티가 크게 어두워집니다. 다시 말해, 증분보다는 루프에서 코드를 최적화하는 것에 대해 걱정하는 것이 훨씬 좋습니다.

제 생각에는 전체 이슈가 단순히 스타일 선호로 요약됩니다. 사전 증분이 더 읽기 쉽다고 생각되면 사용하십시오. 개인적으로, 나는 증분 후를 선호하지만, 아마도 최적화에 대해 알기 전에 내가 배운 것이기 때문일 것입니다.

이것은 조기 최적화의 전형적인 예이며, 이와 같은 문제는 디자인의 심각한 문제에서 우리를 혼란스럽게 할 수 있습니다. 그러나 "모범 사례"에서 사용 또는 합의에있어 통일성이 없기 때문에 여전히 질문하는 것이 좋습니다.


13

둘 다 숫자를 증가시킵니다. ++i와 같습니다 i = i + 1.

i++++i매우 유사하지만 완전히 동일하지 않습니다. 둘 다 숫자를 ++i증가 시키지만 현재 표현식이 평가되기 전에 숫자를 i++증가시키는 반면 , 표현식이 평가 된 후에 숫자를 증가시킵니다.

예:

int i = 1;
int x = i++; //x is 1, i is 2
int y = ++i; //y is 3, i is 3

8

++i(접두사 동작) : 다음을 증가시키고 값 할당
(예를) int i = 5, int b = ++i 이 경우,도 6 (7) 등을 제하고 증분 b에 할당된다.

i++(후위 동작) 다음 할당하고,이 값이 증가
(예 :) int i = 5, int b = i++ 이 경우,도 5 (6) 등을 제하고 증분 b에 할당된다.

for 루프의 경우 : i++일반적으로 ifor 루프에서 증가시키기 전에 시작 값을 사용하기 때문에 주로 사용됩니다 . 그러나 프로그램 논리에 따라 다를 수 있습니다.


7

++i: 사전 증분이고 다른 하나는 증분 후입니다.

i++: 요소를 가져온 다음 증가시킵니다.
++i: i를 증가시킨 다음 요소를 반환합니다.

예:

int i = 0;
printf("i: %d\n", i);
printf("i++: %d\n", i++);
printf("++i: %d\n", ++i);

산출:

i: 0
i++: 0
++i: 2

5

나는 당신이 의미론의 차이점을 이해한다고 가정한다.

그러나 어쨌든 어느 것을 사용 해야하는지에 대해서는 성능 문제를 무시하십시오 .C ++에서도 중요하지 않습니다. 이것이 어느 것을 사용할지 결정할 때 사용해야하는 원칙입니다.

코드에서 의미하는 바를 말하십시오.

명세서에 증가 전 가치가 필요하지 않은 경우 해당 형식의 연산자를 사용하지 마십시오. 사소한 문제이지만 다른 버전을 선호하는 스타일 가이드 (뼈 모양의 스타일 가이드)를 사용하지 않는 한, 수행하려는 작업을 가장 정확하게 표현하는 양식을 사용해야합니다.

QED, 사전 증분 버전을 사용하십시오.

for (int i = 0; i != X; ++i) ...

5

차이점은 아래의 간단한 C ++ 코드로 이해할 수 있습니다.

int i, j, k, l;
i = 1; //initialize int i with 1
j = i+1; //add 1 with i and set that as the value of j. i is still 1
k = i++; //k gets the current value of i, after that i is incremented. So here i is 2, but k is 1
l = ++i; // i is incremented first and then returned. So the value of i is 3 and so does l.
cout << i << ' ' << j << ' ' << k << ' '<< l << endl;
return 0;

5

주요 차이점은

  • i ++ Post ( 증가 후 ) 및
  • ++ i Pre ( 증가 전 )

    • i =1 루프가 다음과 같이 증가 하면 게시1,2,3,4,n
    • i =1 루프가 다음과 같이 증가 하면 pre2,3,4,5,n

5

i ++와 ++ i

이 작은 코드는 이미 게시 된 답변과 다른 각도의 차이를 시각화하는 데 도움이 될 수 있습니다.

int i = 10, j = 10;

printf ("i is %i \n", i);
printf ("i++ is %i \n", i++);
printf ("i is %i \n\n", i);

printf ("j is %i \n", j);
printf ("++j is %i \n", ++j);
printf ("j is %i \n", j);

결과는 다음과 같습니다.

//Remember that the values are i = 10, and j = 10

i is 10 
i++ is 10     //Assigns (print out), then increments
i is 11 

j is 10 
++j is 11    //Increments, then assigns (print out)
j is 11 

전후 상황에주의하십시오.

for 루프

for 루프의 증분 블록에서 어느 쪽을 사용해야하는지에 대해 결정을 내리기 위해 최선을 다하는 것이 좋은 예라고 생각합니다.

int i, j;

for (i = 0; i <= 3; i++)
    printf (" > iteration #%i", i);

printf ("\n");

for (j = 0; j <= 3; ++j)
    printf (" > iteration #%i", j);

결과는 다음과 같습니다.

> iteration #0 > iteration #1 > iteration #2 > iteration #3
> iteration #0 > iteration #1 > iteration #2 > iteration #3 

나는 당신에 대해 모른다. 그러나 적어도 for 루프에서 사용법에 차이가 없다.


5

다음 C 코드 단편은 사전 및 사후 증가 및 감소 연산자의 차이점을 보여줍니다.

int  i;
int  j;

증분 연산자 :

i = 1;
j = ++i;    // i is now 2, j is also 2
j = i++;    // i is now 3, j is 2

4

사전 생성은 동일한 줄에서 증가하는 것을 의미합니다. 후행 증가는 라인이 실행 된 후 증가하는 것을 의미합니다.

int j=0;
System.out.println(j); //0
System.out.println(j++); //0. post-increment. It means after this line executes j increments.

int k=0;
System.out.println(k); //0
System.out.println(++k); //1. pre increment. It means it increments first and then the line executes

OR, AND 연산자를 사용하면 더욱 흥미로워집니다.

int m=0;
if((m == 0 || m++ == 0) && (m++ == 1)) { //false
/* in OR condition if first line is already true then compiler doesn't check the rest. It is technique of compiler optimization */
System.out.println("post-increment "+m);
}

int n=0;
if((n == 0 || n++ == 0) && (++n == 1)) { //true
System.out.println("pre-increment "+n); //1
}

배열에서

System.out.println("In Array");
int[] a = { 55, 11, 15, 20, 25 } ;
int ii, jj, kk = 1, mm;
ii = ++a[1]; // ii = 12. a[1] = a[1] + 1
System.out.println(a[1]); //12

jj = a[1]++; //12
System.out.println(a[1]); //a[1] = 13

mm = a[1];//13
System.out.printf ( "\n%d %d %d\n", ii, jj, mm ) ; //12, 12, 13

for (int val: a) {
     System.out.print(" " +val); //55, 13, 15, 20, 25
}

C ++에서 포인터 변수의 포스트 / 사전 증가

#include <iostream>
using namespace std;

int main() {

    int x=10;
    int* p = &x;

    std::cout<<"address = "<<p<<"\n"; //prints address of x
    std::cout<<"address = "<<p<<"\n"; //prints (address of x) + sizeof(int)
    std::cout<<"address = "<<&x<<"\n"; //prints address of x

    std::cout<<"address = "<<++&x<<"\n"; //error. reference can't re-assign because it is fixed (immutable)
}

4

곧:

++i그리고 i++당신이 함수를 작성하지 않은 경우와 동일하게 작동합니다. 비슷한 것을 사용 function(i++)하거나 function(++i)차이를 볼 수 있습니다.

function(++i)첫 번째 i를 1 씩 증가시킨 다음 i새로운 값으로 함수에 넣습니다.

function(i++)1 i씩 증가한 후 함수 에 먼저 넣습니다 i.

int i=4;
printf("%d\n",pow(++i,2));//it prints 25 and i is 5 now
i=4;
printf("%d",pow(i++,2));//it prints 16 i is 5 now

2
차이점은 실제로 함수 호출과 관련이 없습니다 (함수 호출없이 차이점을 발견 할 수 있음). 함수 호출이없는 경우 int j = ++i;와 차이가 있습니다 int k = i++;.
Jonathan Leffler

3

유일한 차이점은 변수의 증분과 연산자가 반환하는 값 사이의 작업 순서입니다.

이 코드와 그 출력은 차이점을 설명합니다.

#include<stdio.h>

int main(int argc, char* argv[])
{
  unsigned int i=0, a;
  a = i++;
  printf("i before: %d; value returned by i++: %d, i after: %d\n", i, a, i);
  i=0;
  a = ++i;
  printf("i before: %d; value returned by ++i: %d, i after: %d\n", i, a, i);
}

출력은 다음과 같습니다

i before: 1; value returned by i++: 0, i after: 1
i before: 1; value returned by ++i: 1, i after: 1

따라서 기본적으로 ++i값이 증가한 후에 값을 ++i반환하고 값이 증가하기 전에 값 을 반환합니다. 결국 두 경우 모두 i값이 증가합니다.

또 다른 예:

#include<stdio.h>

int main ()
  int i=0;
  int a = i++*2;
  printf("i=0, i++*2=%d\n", a);
  i=0;
  a = ++i * 2;
  printf("i=0, ++i*2=%d\n", a);
  i=0;
  a = (++i) * 2;
  printf("i=0, (++i)*2=%d\n", a);
  i=0;
  a = (++i) * 2;
  printf("i=0, (++i)*2=%d\n", a);
  return 0;
}

산출:

i=0, i++*2=0
i=0, ++i*2=2
i=0, (++i)*2=2
i=0, (++i)*2=2

여러 번 차이가 없습니다

리턴 된 값이 다른 변수에 지정되거나 증분이 조작 우선 순위가 적용되는 ( i++*2다른 값 과 동일 ++i*2하지만 동일한 값을 리턴하는) 다른 조작과 연계하여 수행되는 경우, 많은 경우 교환 할 수 있습니다. 전형적인 예는 for 루프 구문입니다.(i++)*2(++i)*2

for(int i=0; i<10; i++)

같은 효과가있다

for(int i=0; i<10; ++i)

기억해야 할 규칙

두 연산자를 혼동하지 않기 위해이 규칙을 채택했습니다.

++변수 i에 대한 연산자의 위치를 ++할당에 대한 작업 순서 와 연관 시키십시오.

다른 말로하면 :

  • ++ before i 는 할당 전에 증분을 수행해야 함을 의미합니다 .
  • ++ 이후 i 는 할당 후에 증분을 수행해야 함을 의미합니다 .

3

이것의 내부 변환을 여러 문장 으로 생각할 수 있습니다 .

  • 사례 1
i++;

당신은 그것을 생각할 수 있습니다.

i;
i = i+1;
  • 사례 2
++i;

당신은 그것을 생각할 수 있습니다.

i = i+i;
i;

-3

a = i ++는 현재 i 값을 포함 함을 의미합니다. a = ++ i는 증가 된 i 값을 포함 함을 의미합니다.


10
이 답변은 정확하지 않습니다. a = i++;는 저장된 a값이 i증분 이전 의 값을 의미하지만 '증분없이' i는 증분되지 않았 음을 의미합니다 . 이는 완전히 잘못되었습니다. i증분되지만 표현식의 값은 증분 이전의 값입니다.
Jonathan Leffler

-6

차이점을 이해하는 예는 다음과 같습니다.

int i=10;
printf("%d %d",i++,++i);

출력 : 10 12/11 11( printf함수 에 대한 인수 평가 순서에 따라 컴파일러와 아키텍처에 따라 다름)

설명 : i++-> i가 인쇄 된 후 증가합니다. (10을 인쇄하지만 i11이 됨) ++i-> i값이 증가하고 값을 인쇄합니다. (12를 인쇄하고 12 i도 값 )


11
사이에 순서 지점이 없기 때문에이 정의되지 않은 동작이 발생 i++하고++i
MM

@Lundin은 정확하지만, 쉼표의 LHS, RHS는 그들 사이에 시퀀스 포인트가 있지만 2 개의 표현은 여전히 ​​서로 wrt되지 않습니다
Antti Haapala
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.