差がある++i
とi++
でfor
ループが?それは単に構文的なものですか?
差がある++i
とi++
でfor
ループが?それは単に構文的なものですか?
回答:
a ++はpostfixとして知られています。
aに1を加え、古い値を返します。
++ aはプレフィックスとして知られています。
aに1を加え、新しい値を返します。
C#:
string[] items = {"a","b","c","d"};
int i = 0;
foreach (string item in items)
{
Console.WriteLine(++i);
}
Console.WriteLine("");
i = 0;
foreach (string item in items)
{
Console.WriteLine(i++);
}
出力:
1
2
3
4
0
1
2
3
foreach
そしてwhile
ループは、使用されインクリメント種類によって異なります。以下のようなforループでは、iの戻り値を使用しないため、違いはありません。
for (int i = 0; i < 5; i++) { Console.Write(i);}
Console.WriteLine("");
for (int i = 0; i < 5; ++i) { Console.Write(i); }
0 1 2 3 4
0 1 2 3 4
評価された値を使用すると、増分のタイプが重要になります。
int n = 0;
for (int i = 0; n < 5; n = i++) { }
プリインクリメント++ iは、iの値をインクリメントし、新しいインクリメントされた値に評価します。
int i = 3;
int preIncrementResult = ++i;
Assert( preIncrementResult == 4 );
Assert( i == 4 );
ポストインクリメントi ++はiの値をインクリメントし、元のインクリメントされていない値に評価します。
int i = 3;
int postIncrementResult = i++;
Assert( postIncrementtResult == 3 );
Assert( i == 4 );
C ++では、通常、どちらかを使用できる場合、事前増分が推奨されます。
これは、ポストインクリメントを使用する場合、追加の一時変数を作成するコードをコンパイラーが生成する必要があるためです。これは、インクリメントされる変数の以前の値と新しい値の両方が、評価される式の他の場所で必要になる可能性があるため、どこかに保持する必要があるためです。
したがって、少なくともC ++では、どちらを使用するかを選択する際の指針となるパフォーマンスの違いが生じる可能性があります。
これは主に、インクリメントされる変数が、オーバーライドされた++演算子を持つユーザー定義型である場合にのみ問題になります。プリミティブ型(intなど)の場合、パフォーマンスに違いはありません。しかし、ポストインクリメント演算子が明らかに必要なものでない限り、ガイドラインとしてプリインクリメント演算子に固執する価値があります。
ここでいくつかの議論があります:
https //web.archive.org/web/20170405054235/http //en.allexperts.com/q/C-1040/Increment-operators.htm
C ++では、STLを使用している場合は、イテレータを含むforループを使用している可能性があります。これらは主にオーバーライドされた++演算子を持っているので、事前増分に固執することは良い考えです。ただし、コンパイラーは常に賢くなり、新しいコンパイラーは最適化を実行できるため、パフォーマンスの違いはありません。特に、インクリメントされる型が(STL実装がそうであるように)ヘッダーファイルにインラインで定義されている場合は、コンパイラーがどのように見えるかを確認できます。メソッドが実装され、安全に実行できる最適化を知ることができます。それでも、ループは何度も実行されるため、事前増分に固執する価値はあります。これは、わずかなパフォーマンスのペナルティがすぐに増幅される可能性があることを意味します。
++演算子をオーバーロードできないC#などの他の言語では、パフォーマンスに違いはありません。ループ変数を進めるためにループで使用され、事前および事後の増分演算子は同等です。
修正:C#での++のオーバーロードが許可されています。ただし、C ++と比較すると、C#ではプレバージョンとポストバージョンを個別にオーバーロードできないようです。したがって、C#で++を呼び出した結果が変数に割り当てられていないか、複雑な式の一部として使用されていない場合、コンパイラーは++の前バージョンと後バージョンを同等に機能するコードに削減すると考えます。
C#では、forループで使用しても違いはありません。
for (int i = 0; i < 10; i++) { Console.WriteLine(i); }
同じものを出力します
for (int i = 0; i < 10; ++i) { Console.WriteLine(i); }
他の人が指摘したように、一般的に使用される場合、i ++と++ iには微妙ですが重要な違いがあります。
int i = 0;
Console.WriteLine(i++); // Prints 0
int j = 0;
Console.WriteLine(++j); // Prints 1
i ++はiの値を読み取り、それを増分します。
++ iはiの値を増分し、それを読み取ります。
++i
とi++
同じ順序で同じ操作を実行する:の一時コピーを作成しますi
。temp値をインクリメントして新しい値を生成します(tempを上書きしないため)。新しい値をに保存しi
ます。これ++i
が結果の場合、返される結果は新しい値です。その場合i++
、返される結果は一時コピーです。ここでより詳細な回答:stackoverflow.com/a/3346729/3330348
質問は:
forループで++ iとi ++に違いはありますか?
答えは次のとおりです。いいえ。
これが求められていないのに、なぜ他のすべての回答が事前および事後のインクリメントに関する詳細な説明に入らなければならないのですか?
このforループ:
for (int i = 0; // Initialization
i < 5; // Condition
i++) // Increment
{
Output(i);
}
ループを使用せずにこのコードに変換します:
int i = 0; // Initialization
loopStart:
if (i < 5) // Condition
{
Output(i);
i++ or ++i; // Increment
goto loopStart;
}
ここに置くi++
か++i
、ここに追加するかは重要ですか?いいえ、インクリメント操作の戻り値は重要ではないため、そうではありません。i
forループ本体内にあるコードの実行後に増分されます。
あなたはループの違いについて尋ねるので、私はあなたが意味していると思います
for(int i=0; i<10; i++)
...;
その場合、ほとんどの言語で違いはありません。ループは、i++
およびを記述して++i
いるかどうかに関係なく同じように動作します。C ++では、独自のバージョンの++演算子を記述できます。これi
がユーザー定義型(独自のクラスなど)の場合は、それらに個別の意味を定義できます。
上記が問題にならない理由は、の値を使用しないためですi++
。もう一つはあなたがするときです
for(int i=0, a = 0; i<10; a = i++)
...;
今、そこにいる他の人が指摘するように、ので違いは、i++
意味増分が、以前の値に評価されますが、++i
手段の増加、それに評価するi
(したがって、それは新しい値に評価されます)。上記の場合a
は、iの前の値が割り当てられますが、iはインクリメントされます。
このコードが示すように(コメントの解読されたMSILを参照)、C#3コンパイラはforループでi ++と++ iを区別しません。i ++または++ iの値が使用されている場合、間違いなく違いがあります(これはVisutal Studio 2008 /リリースビルドでコンパイルされました)。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace PreOrPostIncrement
{
class Program
{
static int SomethingToIncrement;
static void Main(string[] args)
{
PreIncrement(1000);
PostIncrement(1000);
Console.WriteLine("SomethingToIncrement={0}", SomethingToIncrement);
}
static void PreIncrement(int count)
{
/*
.method private hidebysig static void PreIncrement(int32 count) cil managed
{
// Code size 25 (0x19)
.maxstack 2
.locals init ([0] int32 i)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0014
IL_0004: ldsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0010: ldloc.0
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.0
IL_0014: ldloc.0
IL_0015: ldarg.0
IL_0016: blt.s IL_0004
IL_0018: ret
} // end of method Program::PreIncrement
*/
for (int i = 0; i < count; ++i)
{
++SomethingToIncrement;
}
}
static void PostIncrement(int count)
{
/*
.method private hidebysig static void PostIncrement(int32 count) cil managed
{
// Code size 25 (0x19)
.maxstack 2
.locals init ([0] int32 i)
IL_0000: ldc.i4.0
IL_0001: stloc.0
IL_0002: br.s IL_0014
IL_0004: ldsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0009: ldc.i4.1
IL_000a: add
IL_000b: stsfld int32 PreOrPostIncrement.Program::SomethingToIncrement
IL_0010: ldloc.0
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.0
IL_0014: ldloc.0
IL_0015: ldarg.0
IL_0016: blt.s IL_0004
IL_0018: ret
} // end of method Program::PostIncrement
*/
for (int i = 0; i < count; i++)
{
SomethingToIncrement++;
}
}
}
}
1つ(++ i)はプリインクリメントで、1つ(i ++)はポストインクリメントです。違いは、式からすぐに返される値です。
// Psuedocode
int i = 0;
print i++; // Prints 0
print i; // Prints 1
int j = 0;
print ++j; // Prints 1
print j; // Prints 1
編集:うーん、物事のループ側を完全に無視しました。forループが「ステップ」部分(for(...; ...;))の場合、実際にはforループに違いはありませんが、それ以外の場合にも機能します。
ループでインクリメント後の値を使用しない場合、違いはありません。
for (int i = 0; i < 4; ++i){
cout<<i;
}
for (int i = 0; i < 4; i++){
cout<<i;
}
両方のループで0123が出力されます。
ただし、ループでインクリメント/デクリメントした後の値を次のように使用すると、違いが生じます。
事前増分ループ:
for (int i = 0,k=0; i < 4; k=++i){
cout<<i<<" ";
cout<<k<<" ";
}
出力:0 0 1 1 2 2 3 3
ポストインクリメントループ:
for (int i = 0, k=0; i < 4; k=i++){
cout<<i<<" ";
cout<<k<<" ";
}
出力:0 0 1 0 2 1 3 2
出力を比較することで、違いが明確になることを願っています。ここで注意すべき点は、インクリメント/デクリメントは常にforループの最後に実行されるため、結果を説明できるということです。
以下はJavaサンプルであり、バイトコード、ポストおよびプレインクリメントはバイトコードに違いを示していません。
public class PreOrPostIncrement {
static int somethingToIncrement = 0;
public static void main(String[] args) {
final int rounds = 1000;
postIncrement(rounds);
preIncrement(rounds);
}
private static void postIncrement(final int rounds) {
for (int i = 0; i < rounds; i++) {
somethingToIncrement++;
}
}
private static void preIncrement(final int rounds) {
for (int i = 0; i < rounds; ++i) {
++somethingToIncrement;
}
}
}
そして今バイトコードのために(javap -private -c PreOrPostIncrement):
public class PreOrPostIncrement extends java.lang.Object{
static int somethingToIncrement;
static {};
Code:
0: iconst_0
1: putstatic #10; //Field somethingToIncrement:I
4: return
public PreOrPostIncrement();
Code:
0: aload_0
1: invokespecial #15; //Method java/lang/Object."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: sipush 1000
3: istore_1
4: sipush 1000
7: invokestatic #21; //Method postIncrement:(I)V
10: sipush 1000
13: invokestatic #25; //Method preIncrement:(I)V
16: return
private static void postIncrement(int);
Code:
0: iconst_0
1: istore_1
2: goto 16
5: getstatic #10; //Field somethingToIncrement:I
8: iconst_1
9: iadd
10: putstatic #10; //Field somethingToIncrement:I
13: iinc 1, 1
16: iload_1
17: iload_0
18: if_icmplt 5
21: return
private static void preIncrement(int);
Code:
0: iconst_0
1: istore_1
2: goto 16
5: getstatic #10; //Field somethingToIncrement:I
8: iconst_1
9: iadd
10: putstatic #10; //Field somethingToIncrement:I
13: iinc 1, 1
16: iload_1
17: iload_0
18: if_icmplt 5
21: return
}
はいあります。違いは戻り値にあります。「++ i」の戻り値はi をインクリメントした後の値になります。「i ++」の戻り値はインクリメント前の値になります。これは、次のようなコードを意味します。
int a = 0;
int b = ++a; // a is incremented and the result after incrementing is saved to b.
int c = a++; // a is incremented again and the result before incremening is saved to c.
したがって、aは2、bとcはそれぞれ1になります。
私はこのようにコードを書き直すことができます:
int a = 0;
// ++a;
a = a + 1; // incrementing first.
b = a; // setting second.
// a++;
c = a; // setting first.
a = a + 1; // incrementing second.
++ iとi ++には、ループとパフォーマンスの違いだけではありません。++ iはl値を返し、i ++はr値を返します。これに基づいて、(++ i)にはできるが(i ++)にはできないことがたくさんあります。
1- It is illegal to take the address of post increment result. Compiler won't even allow you.
2- Only constant references to post increment can exist, i.e., of the form const T&.
3- You cannot apply another post increment or decrement to the result of i++, i.e., there is no such thing as I++++. This would be parsed as ( i ++ ) ++ which is illegal.
4- When overloading pre-/post-increment and decrement operators, programmers are encouraged to define post- increment/decrement operators like:
T& operator ++ ( )
{
// logical increment
return *this;
}
const T operator ++ ( int )
{
T temp( *this );
++*this;
return temp;
}
それはなぜ人々がforループでインクリメント式をi ++として書くのか、なぜか私の心を揺さぶります。
forループで、3番目のコンポーネントが次のように単純なインクリメントステートメントである場合
for (i=0; i<x; i++)
または
for (i=0; i<x; ++i)
結果の実行に違いはありません。
@ジョンBが言う、forループに違いはありません。
しかし、中にwhile
またはdo...while
あなたがと比較して作っている場合はループ、あなたはいくつかの相違点を見つけることができる++i
かをi++
while(i++ < 10) { ... } //compare then increment
while(++i < 10) { ... } //increment then compare
JavaScriptでは、次の理由により、i ++を使用する方がよい場合があります。
var i=1;
alert(i++); // before, 1. current, 1. after, 2.
alert(i); // before, 2. current, 2. after, 2.
alert(++i); // before, 2. current, 3 after, 3.
配列(私はすべてだと思います)と他のいくつかの関数と呼び出しは開始点として0を使用しますが、++ iを使用するときにループを配列で機能させるには、iを-1に設定する必要があります。
使用するときは、私を++、以下の値が増加した値を使用します。i ++は人間が数える方法だと言えるかもしれません、なぜなら0から始めることができるからです。
FORループの機能を理解するには
上記の画像は、FORがWHILEに変換できることを示しています。これらは最終的に完全に同じアセンブリコード(少なくともgcc)を持つためです。したがって、FORをいくつかの部分に分解して、その機能を理解することができます。
for (i = 0; i < 5; ++i) {
DoSomethingA();
DoSomethingB();
}
WHILEバージョンと等しい
i = 0; //first argument (a statement) of for
while (i < 5 /*second argument (a condition) of for*/) {
DoSomethingA();
DoSomethingB();
++i; //third argument (another statement) of for
}
これは、FORをWHILEの単純なバージョンとして使用できることを意味します。
FOR(int i)の最初の引数は、ループの前に、外側で実行されます。
FORの3番目の引数(i ++または++ i)は、ループの最後の行で実行されます。
TL:DR:どんなにかどう
i++
か++i
に、スタンドアロンの場合、違いはなく、+ 1します。学校では通常、i ++の方法を教えていますが、いくつかの理由により、++ iの方法を好む人もたくさんいます。
注:以前は、i ++はそれ自体に1を加えるだけでなく、元の値をレジスターに保持するため、パフォーマンスへの影響はほとんどありませんでした。しかし、今のところ、コンパイラーがプラスワンパーツを同じにするため、違いはありません。
ループには違いがある場合があります。これは、ポスト/プリインクリメントの実用的なアプリケーションです。
int i = 0;
while(i++ <= 10) {
Console.Write(i);
}
Console.Write(System.Environment.NewLine);
i = 0;
while(++i <= 10) {
Console.Write(i);
}
Console.ReadLine();
最初のものは11まで数え、11回ループしますが、2つ目はそうではありません。
ほとんどの場合、これは単純なwhile(x--> 0)で使用されます。--ループして、たとえば配列のすべての要素を反復します(ここではforeach-constructsを除く)。
はい、の間に差がある++i
とi++
でfor
ループが異常なユースケースでも、。インクリメント/デクリメント演算子を含むループ変数がforブロックまたはループテスト式内で使用された場合、またはループ変数の1つで使用された場合。いいえ、それは単に構文的なものではありません。
i
コードのように、式i
を評価することを意味し、演算子は評価を意味するのではなく、操作を意味します。
++i
の値をi
1増やしi
、後で評価することを意味します。i++
評価しi
、後で値をi
1 ずつ増分することを意味します。したがって、評価されるものはそれぞれ異なるため、2つの式から得られるものは異なります。すべて同じ--i
とi--
例えば;
let i = 0
i++ // evaluates to value of i, means evaluates to 0, later increments i by 1, i is now 1
0
i
1
++i // increments i by 1, i is now 2, later evaluates to value of i, means evaluates to 2
2
i
2
通常とは異なる使用例では、次の例が役立つかどうかは関係ありませんが、違いを示しています
for(i=0, j=i; i<10; j=++i){
console.log(j, i)
}
for(i=0, j=i; i<10; j=i++){
console.log(j, i)
}
以下のためのi
ユーザー定義型のの、これらの演算子はできた(ただし、いけません)ループインデックスの文脈における意味の異なるsematicsを有し、これは可能性(しかしならない)説明ループの動作に影響を与えます。
また、c++
プリインクリメントフォーム(++i
)を使用すると、最適化が容易になるため、一般的に最も安全です。(スコット・ランガムは私をこの一口に殴りました。あなたを呪い、スコット)