C:++ iとi ++の違いは何ですか?


888

Cにおいて、使用の違いは何である++ii++、とのインクリメントブロックにおいて使用すべきforループは?


10
元の投稿者が興味を持っているかどうかはわかりませんが、C ++では、一時オブジェクトの作成にユーザー定義の型のコストがかかる可能性があるため、パフォーマンスの違いが大きくなる可能性があります。
フロイント2008年

回答:


1101
  • ++iの値をインクリメントし、インクリメントした値をi返します。

     i = 1;
     j = ++i;
     (i is 2, j is 2)
  • i++の値をインクリメントしますがiiインクリメントされる前に保持されていた元の値を返します。

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

以下のため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、2011

27
jonnyflashは、iの増分と出力が異なるステートメントであるため、どちらも同じように動作します。これは、Cスタイルの++をサポートするすべての言語に当てはまります。++ iとi ++の唯一の違いは、同じステートメントで操作の値を使用する場合です。
Mark Harrison

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が最初のコメントで説明した方法とは異なる動作をします。
アダム

3
@sam。これは、一般的なforループでは、++ i部分に副作用(たとえば、割り当て)がないためです。
マークハリソン

175

++ iPre Incrementと呼ばれるのに対し、i ++Post Incrementとして知られています。

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(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
プレフィックスとポストフィックスの後に変数を初期化すると理解しやすくなります。ありがとう。
Abdul Alim Shakir、2018

42

どちらがより速いかという「効率」(実際には速度)について心配しないでください。最近、これらのことを処理するコンパイラーがあります。あなたの意図をより明確に示すものに基づいて、使用するのに意味のある方を使用してください。


1
これは、「(inc | dec)より前の古い値が実際に必要な場合を除いて、接頭辞(inc | dec)リメントを使用することを意味します。それが何であるかさえ知らないPostfixユーザーのカーゴカルトを作成する '。!!
underscore_d

「最近のコンパイラー…これらのことを処理する」が普遍的に真実であるかどうかはわかりません。カスタムoperator++(int)(postfixバージョン)内では、コードは一時的なものを作成し、それを返す必要があります。コンパイラは常にそれを最適化できると確信していますか?
ピーター-モニカを復活させる

36

++i 値をインクリメントしてから返します。

i++ 値を返し、それを増分します。

微妙な違いです。

forループの場合は++i、少し高速なので、を使用します。i++捨てられるだけの余分なコピーを作成します。


23
少なくとも整数で違いが出るコンパイラについては知りません。
blabla999 2009年

4
それは速くありません。値は無視され(副作用のみが有効です)、コンパイラーはまったく同じコードを生成できます。
wildplasser 2017年

31

i++:このシナリオでは、最初に値が割り当てられ、次に増分が発生します。

++i:このシナリオでは、最初に増分が行われ、次に値が割り当てられます

以下は画像の視覚化であり、ここにも同じことを示す素晴らしい実用的なビデオがあります。

ここに画像の説明を入力してください


割り当てられていないものをいくら増加させることができますか
コウティ

@kouty変数に割り当てられていないレジスタをインクリメントできます。
Polluks

20

その理由は、++i することができ、わずかに速くよりもi++それがあるi++一方で、それがインクリメントされる前にiの値のローカルコピーを必要とすることができます++iませんでした。場合によっては、一部のコンパイラーは、可能であればそれを最適化します...しかし、常に可能であるとは限りません。すべてのコンパイラーがこれを行うわけではありません。

コンパイラーの最適化にあまり依存しないように心がけているので、Ryan Foxのアドバイスに従います++i。両方を使用できる場合は、を使用します。


11
Cの質問に対するC ++回答の場合は-1 iステートメントを記述したとき、値の「ローカルコピー」は値1の値よりも多くありません1;
R .. GitHub ICEのヘルプの停止

14

どちらかをループで使用した場合の効果的な結果は同じです。つまり、ループは両方のインスタンスでまったく同じことを行います。

効率の点では、++ iよりもi ++を選択するとペナルティが生じる可能性があります。言語仕様に関して、ポストインクリメント演算子を使用すると、演算子が作用する値の追加のコピーが作成されます。これは追加の操作のソースになる可能性があります。

ただし、前述のロジックでは2つの主要な問題を考慮する必要があります。

  1. 最新のコンパイラは素晴らしいです。すべての優れたコンパイラーは、forループで整数のインクリメントが見られることを認識するのに十分スマートであり、両方のメソッドを同じ効率的なコードに最適化します。プリインクリメントよりポストインクリメントを使用すると、プログラムの実行時間が長くなる場合は、ひどいコンパイラを使用しています。

  2. 運用時間の複雑さに関しては、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 = 5int b = ++i この場合には、図6に示すように7等に第1および増分をbに割り当てられます。

i++(Postfixの動作)次に割り当て、値をインクリメント
(例えば)int i = 5int b = i++ ここで、5は6等に第1および増分をbに割り当てられます。

forループの場合:i++通常使用されるのはi、forループでインクリメントする前の開始値を使用するためです。ただし、プログラムのロジックによって異なります。


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

私はあなたがセマンティクスの違いを理解していると思います(正直に言って、本やWebチュートリアルなどを読むのではなく、スタックオーバーフローについて人々が「演算子Xの意味」の質問をするのはなぜでしょうか?

しかしとにかく、どちらを使用するかについては、C ++でも重要ではないパフォーマンスの問題を無視してください。これは、どちらを使用するかを決定するときに使用する必要がある原則です。

コードであなたが意味することを言ってください。

ステートメントでvalue-before-incrementが必要ない場合は、その形式の演算子を使用しないでください。これは小さな問題ですが、1つのバージョンを完全に他のバージョンよりも優先するスタイルガイド(つまり、骨のあるスタイルガイド)で作業しているのでない限り、実行しようとしていることを最も正確に表すフォームを使用する必要があります。

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++)最初ii1 ずつインクリメントした後に関数に入れると言います。

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、2015年

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が同じ値(i++)*2(++i)*2返す)他の演算と連結してインクリメントが実行される場合、多くの場合、それらは交換可能です。古典的な例はforループ構文です:

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

同じ効果があります

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

覚えておくべきルール

2つの演算子を混同しないように、私はこのルールを採用しました。

++変数に関する演算子の位置を、割り当てに関する操作iの順序に++関連付けます

言い換えれば:

  • ++ before iは、インクリメントを割り当てに実行する必要があることを意味します。
  • ++ after 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、2015年

-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つの式は互いに順序付けられていません
Antti Haapala 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.