Cのi ++と++ iの間にパフォーマンスの違いはありますか?


回答:


397

エグゼクティブサマリー:いいえ。

i++++iの古い値i を後で使用するために保存する必要があるため、はよりも遅くなる可能性がありますが、実際には、最近のすべてのコンパイラはこれを最適化します。

我々は両方で、この関数のコードを見て、これを実証することができます++iし、i++

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

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

}

++iおよびを除いて、ファイルは同じですi++

$ 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に関するものであることを知っていますが、ブラウザーがこのJavaScriptの最適化を行えるかどうか知りたいです。
TM。

69
したがって、「いいえ」は、テストに使用した1つのコンパイラに当てはまります。
Andreas

173
@Andreas:いい質問ですね。私はコンパイラライターでしたが、このコードを多くのCPU、オペレーティングシステム、コンパイラでテストする機会がありました。i ++のケースを最適化しないことがわかったコンパイラー(実際、これを専門的に注目させたコンパイラー)は、Walt BilofskyによるSoftware Toolworks C80コンパイラーでした。そのコンパイラはIntel 8080 CP / Mシステム用でした。この最適化を含まないコンパイラは一般的な使用を意図したものではないと言っても安全です。
Mark Harrison、

22
パフォーマンスの違いはごくわずかで、多くの場合最適化されていますが、の++i代わりに使用することをお勧めしますi++。絶対にしない理由はありません。ソフトウェアがそれを最適化しないツールチェーンを通過する場合、ソフトウェアはより効率的になります。それが入力するだけの簡単なようで考えると++i、それは型にあるとしてi++、使用されないように言い訳は本当にありません++i最初の場所では。
12

7
@monokrome開発者は多くの言語で前置演算子と後置演算子の独自の実装を提供できるため、これらの関数を最初に比較せずに作成するコンパイラにとって、これは必ずしも容認できない解決策になる可能性があります。
pickypg 2012

112

Andrew Koenigによる効率と意図から:

第1に、少なくとも整数変数が関係している++i場合i++、がより効率的であることは明らかではありません。

そして:

したがって、質問する必要があるのは、これら2つの操作のどちらが速いかではなく、これら2つの操作のどちらが、達成しようとしていることをより正確に表現しているかということです。式の値を使用していない場合、変数の値をコピーし、変数をインクリメントしてからコピーを破棄する理由がないため、のi++代わりに使用++iする理由はありません。

したがって、結果の値が使用されない場合は、を使用します++i。しかし、それがより効率的だからではありません。それは、私の意図を正しく述べているからです。


5
他の単項演算子も接頭辞であることを忘れないでください。++ iは単項演算子を使用する「セマンティック」な方法だと思いますが、i ++は特定のニーズ(追加前の評価)に合わせるためにあります。
TM。

9
結果の値が使用されない場合、セマンティクスに違いはありません。つまり、どちらか一方の構成を優先する根拠がありません。
Eamon Nerbonne

3
読者として、私は違いを見ます。だから私は作家として、どちらか一方を選ぶことで私の意図を示します。それは:)コードを私のプログラマの友人やチームメイトと通信しようと、私は持っているだけの習慣だ
セバスチャン・RoccaSerra

11
Koenigのアドバイスに従って、またはi++と同じ方法で、つまりターゲット動詞オブジェクトの形式で、ターゲットオペランドを動詞演算子の左側にコーディングします。の場合、正しいオブジェクトはありませんが、ルールは適用され、ターゲット動詞演算子の左側に配置されます。i += ni = i + n i++
David R Tribble 2014年

4
iをインクリメントしようとしている場合、i ++と++ iの両方が意図を正しく表します。どちらか一方を優先する理由はありません。読者は私に違いはないと思いますが、同僚がi ++を見て混乱するのではないでしょうか。おそらく、これはタイプミスであり、彼はiを増やすつもりはなかったのでしょうか。
ダンカーター、2014

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 2008年

5
この(確かに古い)質問はC ++ではなくCに関するものでしたが、C ++では、クラスが後置演算子と前置演算子を実装している場合でも、それらが必ずしも関連しているわけではないことにも言及する価値があると思います。たとえば、bar ++は1つのデータメンバーをインクリメントする可能性がありますが、++ barは別のデータメンバーをインクリメントする可能性があります。この場合、セマンティクスが異なるため、どちらも使用できません。
Kevin

-1これはC ++プログラマーには良いアドバイスですが、Cというタグが付いた質問には少しも答えません。Cでは、プレフィックスとポストフィックスのどちらを使用しても、まったく違いはありません。
ランディン2014年

@Pacerier質問のタグはCで、Cのみです。なぜ彼らはそれに興味がないと思いますか?SOがどのように機能するかを考えると、Java、C#、COBOL、またはその他のトピック外の言語ではなく、C のみに関心があると想定する方が賢明ではないでしょうか。
Lundin

18

簡潔な答え:

間に違いはあり決してありませんi++し、++i速度の点では。優れたコンパイラは、2つのケースで異なるコードを生成するべきではありません。

長い答え:

どのような他のすべての答えが言及に失敗したこととの違いということである++i対がi++唯一それが発見された式の中で理にかなっています。

以下の場合にはfor(i=0; i<n; i++)i++独自の表現で一人である:前のシーケンスポイントがありi++、それの後に1があります。このように生成された唯一のマシンコードは、「増加であるiことで1、それは、このプログラムの残りの部分に関連して配列決定する方法を明確に定義されています」。あなたは接頭辞に変更するかどうので++、それは問題ではわずかで、あなたはまだ、単に「増加マシンコードになるだろうしませんi1」。

間の違い++ii++のような表現で唯一の事項array[i++] = x;に対してarray[++i] = x;i常駐するレジスタを後で再ロードする必要があるため、そのような操作ではpostfixが遅くなると主張して言う人もいます。ただし、C標準で呼ばれている「抽象マシンの動作を壊さない」限り、コンパイラは自由に命令を自由に順序付けできることに注意してください。

したがって、次のarray[i++] = x;ようにマシンコードに変換されると想定する場合があります。

  • の値をiレジスタAに格納します。
  • 配列のアドレスをレジスターBに格納します。
  • AとBを追加し、結果をAに格納します。
  • Aで表されるこの新しいアドレスに、xの値を格納します。
  • iレジスタAに値を格納します。//ここに追加の命令があるため、これはすでに1回実行したためです。
  • レジスタAをインクリメントします。
  • レジスタAをに格納しiます。

コンパイラは、次のようなコードをより効率的に生成することもできます。

  • の値をiレジスタAに格納します。
  • 配列のアドレスをレジスターBに格納します。
  • AとBを追加し、結果をBに保存します。
  • レジスタAをインクリメントします。
  • レジスタAをに格納しiます。
  • ... //コードの残りの部分。

Cプログラマとして、postfix ++が最後に起こると考えるように訓練されているからといって、マシンコードをそのように順序付ける必要はありません。

したがって++、Cの接頭辞と接尾辞の間に違いはありません。Cプログラマとしてあなたが変える必要があるのは、理由のない根拠なしに、場合によっては接頭辞を使用し、他の場合には接尾辞を一貫して使用しない人です。これは、Cがどのように機能するかについて不確実であること、または言語についての誤った知識を持っていることを示唆しています。これは常に悪い兆候であり、迷信または「宗教的教義」に基づいて、プログラムで他の疑わしい決定を行っていることを示しています。

「プレフィックス++は常に速い」は、Cプログラマになる可能性の高いプログラマーの間でよくある偽の教義です。


3
「Prefix ++は常に速い」とは誰も言っていません。それは間違って引用されています。彼らが言ったのは「Postfix ++は決して速くない」ということでした
Pacerier、2015

2
@Pacerier私は特定の人を引用しているのではなく、広く普及している誤った信念を引用しています。
Lundin

@rbaleksandar C ++!= C.
ランディン

@rbaleksandar質問と回答の両方がC ++について話します。それはオペレータのオーバーロードやその他のコンストラクタをコピーしているので、Cとは異なっている
ランディン

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

17

スコット・マイヤーズ、より効果的なc ++の 項目6からリーフを取得:増分演算と減分演算のプレフィックス形式とポストフィックス形式を区別します

オブジェクトに関しては、特にイテレータに関しては、接頭辞バージョンが常に接尾辞よりも優先されます。

演算子の呼び出しパターンを見ると、この理由があります。

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

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

この例を見ると、前置演算子が後置演算子よりも常に効率的であることが簡単にわかります。postfixの使用には一時オブジェクトが必要なため。

これが、イテレータを使用する例を見るとき、常にプレフィックスバージョンを使用する理由です。

しかし、intについて指摘したように、コンパイラーの最適化が行われるため、実際には違いはありません。


4
彼の質問はCに向けられたと思いますが、C ++の場合は完全に正しいです。さらに、Cの人もC ++にも使用できるため、Cの人はこれを採用する必要があります。Cのプログラマがpostfix構文を使用するのを私はよく見かけます;-)
Anders Rune Jensen

-1これはC ++プログラマーには良いアドバイスですが、Cというタグが付いた質問には少しも答えません。Cでは、プレフィックスとポストフィックスのどちらを使用しても、まったく違いはありません。
ランディン2014年

1
Andreasの回答によると、@ Lundin接頭辞とpostifxはCでは重要です。コンパイラーが最適化されると想定することはできません。Alwasがi ++よりも++ iを好むのは
JProgrammer

@JProgrammer彼らの回答によると、彼らは心から関係ありません:)最適化を有効にできなかったか、コンパイラが悪いため、異なるコードが生成されることがわかった場合。質問はC.についてだったとしてとにかく、あなたの答えは、オフトピックです
ランディン

16

マイクロ最適化が心配な場合の追加の観察結果を以下に示します。ループのデクリメントは、(おそらくARMのような命令セットアーキテクチャに応じて)インクリメントループよりも「効率的」です。

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

ループごとに、それぞれに対して1つの命令があります。

  1. に追加1していiます。
  2. iがより小さいかどうかを比較し100ます。
  3. iがより小さい場合の条件付きブランチ100

一方、デクリメントループ:

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

ループには次のそれぞれに対する命令があります。

  1. デクリメントi、CPUレジスタステータスフラグを設定。
  2. CPUレジスタのステータスに応じた条件付きブランチ(Z==0)。

もちろん、これはゼロにデクリメントするときにのみ機能します!

ARMシステム開発者ガイドから覚えています。


いいね。しかし、これによりキャッシュヒットが減少しませんか?
AndreasT 2009

コード最適化の本には、奇妙なトリックがあり、ゼロテストブランチの利点とインクリメントされたアドレスを組み合わせています。高水準言語の例を次に示します(多くのコンパイラは、効率が低くても一般的なループコードに置き換えるのに十分なほどスマートであるため、おそらく役に立たないでしょう):int a [N]; for(i = -N; i; ++ i)a [N + i] + = 123;
noop

@noopは、どのコード最適化ブックを参照するかについて詳しく説明できますか?良いものを見つけるのに苦労しました。
12

7
この答えは質問に対する答えではありません。
12

@mezamorphic x86の場合、私のソースはIntel最適化マニュアル、Agner Fog、Paul Hsieh、Michael Abrashです。
noop

11

どちらを使用するかは、「どちらが速いか」の問題にしないでください。そんなに気にすることは決してないだろうし、それに加えて、プログラマーの読み取り時間はマシン時間よりもはるかに高くつく。

コードを読む人間にとって最も意味のあるものを使用してください。


3
私は、実際の効率の向上や意図の全体的な明確さよりも、あいまいな読みやすさの改善を好むのは間違っていると思います。
noop

4
私の用語「プログラマーの読書時間」は、「意図の明確さ」とほぼ同じです。「実際の効率の向上」は計り知れないことが多く、ゼロと呼ぶのに十分なほどゼロに近い。OPの場合、++ iがボトルネックであることをコードがプロファイルしていない限り、どちらが速いかという問題は、時間の浪費とプログラマーの思考の単位です。
アンディレスター

2
++ iとi ++の読みやすさの違いは個人的な好みの問題にすぎませんが、最適化コンパイラーが関与する場合、些細なケースと単純なデータ型の結果は同等ですが、++ iは明らかにi ++よりも単純な操作を意味します。したがって、ポストインクリメントの特定のプロパティが必要ない場合、++ iは私にとって勝者です。
noop

あなたは私が言っていることを言っています。「効率」を気にするよりも、意図を示して読みやすさを向上させることが重要です。
アンディレスター2010

2
まだ同意できません。優先度のリストで可読性が高い場合は、プログラミング言語の選択が間違っている可能性があります。C / C ++の主な目的は、効率的なコードを書くことです。
noop 2013

11

まず、C i++との違い++iはCではごくわずかです。


詳細へ。

1.よく知られているC ++の問題:++iより速い

C ++では、++iより効率的なのiは、オーバーロードされたインクリメント演算子を持つオブジェクトの一種です。

どうして?
では++i、オブジェクトは最初にインクリメントされ、その後、他の関数へのconst参照として渡すことができます。これは、式が呼び出されるfoo(i++)前にインクリメントを実行する必要があるために式がそうである場合は不可能ですfoo()が、古い値をに渡す必要がありますfoo()。その結果、コンパイラーは、i、オリジナルでインクリメント演算子を実行する前にのます。追加のコンストラクタ/デストラクタ呼び出しは悪い部分です。

上記のように、これは基本的なタイプには適用されません。

2.あまり知られていない事実:速いi++ かもしれない

コンストラクタ/デストラクタは、常にCの場合である、呼び出す必要がない場合、++iおよびi++、右も同様に高速である必要がありますか?いいえ。それらは事実上同等に高速ですが、小さな違いがある可能性があり、他のほとんどの回答者が間違った方法で回避しました。

どうすれi++ば速くなることができますか?
ポイントはデータの依存関係です。値をメモリからロードする必要がある場合、2つの後続の操作を使用して、値を増分し、使用する必要があります。では++i、値を使用する前にインクリメントを行う必要があります。でi++、使用が増加に依存せず、CPUは使用操作を実行することができる並列にインクリメント動作。違いはせいぜい1 CPUサイクルなので、それは実際には無視できますが、それはあります。そして、それは多くの人が期待するであろう逆の方法です。


あなたのポイントについて2:++iまたはi++が別の式内で使用されている場合、それらの間で変更すると式のセマンティクスが変更されるため、パフォーマンスの向上/損失の可能性は問題外です。それらがスタンドアロンである場合、つまり、操作の結果がすぐに使用されない場合、適切なコンパイラはそれを同じもの、たとえばINCアセンブリ命令にコンパイルします。
Shahbaz 2015

1
@Shahbazそれは完全に真実ですが、要点ではありません。1)セマンティクスは異なりますが、両方でi++あり、++iループ定数を1つ調整することにより、ほぼすべての状況で互換的に使用できるため、プログラマーが行うこととほぼ同じです。2)どちらも同じ命令にコンパイルされますが、CPUの実行は異なります。の場合i++、CPU は同じ値を使用する他のいくつかの命令と並行して増分計算できます(CPUは実際にこれを実行します)。一方++i、CPUでは、増分後に他の命令をスケジュールする必要があります。
cmaster-2015年

4
@Shahbaz例として:if(++foo == 7) bar();if(foo++ == 6) bar();機能的に同等です。ただし、比較と増分はCPUで並行して計算できるため、2番目の方が1サイクル速くなる場合があります。この単一のサイクルは重要ではありませんが、違いはあります。
cmaster-2015年

1
いい視点ね。定数は、通常使用される場所(および<vsなど<=)に多く表示さ++れるため、theth間の変換は、多くの場合簡単に可能です。
Shahbaz

1
私はポイント2が好きですが、値が使用されている場合にのみ適用されます。「結果の値が使用されない場合」という質問は混乱を招く可能性があります。
jinawee

7

@Markコンパイラーは変数の(スタックベースの)一時的なコピーを最適化することを許可されており、gcc(最近のバージョンでは)は最適化していますが、すべてのコンパイラーが常に最適化するわけではありません。

現在のプロジェクトで使用しているコンパイラでテストしたところ、4つのうち3つは最適化していません。

コンパイラが正しく機能しているとは決して想定しないでください。特に、コードが読みやすくなる可能性はありますが、速度が遅くなる可能性がある場合は特にそうです。

コード内の演算子の1つの本当に愚かな実装がない場合:

Alwasはi ++よりも++ iを好みます。


ちょっと気になる...なぜあなたは1つのプロジェクトで4つの異なるCコンパイラを使うのですか?それとも、1つのチームまたは1つの会社でですか。
Lawrence Dol 2013年

3
コンソール用のゲームを作成する場合、すべてのプラットフォームに独自のコンパイラー/ツールチェーンが用意されています。完璧な世界では、すべてのターゲットにgcc / clang / llvmを使用できますが、この世界ではMicrosoft、Intel、Metroworks、Sonyなどに我慢する必要があります
Andreas

5

Cでは、結果が未使用の場合、コンパイラーは通常、それらを同じになるように最適化できます。

ただし、C ++では、独自の++演算子を提供する他の型を使用している場合、接頭辞バージョンの方が後置バージョンよりも高速になる可能性があります。そのため、postfixセマンティクスが必要ない場合は、前置演算子を使用することをお勧めします。


4

接頭辞の増分よりも接尾辞が遅い状況を考えることができます。

レジスタ付きのプロセッサが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]

Postfixの増分:

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に強制的にリロードされた。プレフィックスインクリメントを使用すると、コンパイラは値をインクリメントして使用を続行できます。インクリメント後に目的の値がすでにレジスタにあるため、リロードを回避できます。ただし、後置インクリメントでは、コンパイラーは2つの値を処理する必要があります。1つは古い値で、もう1つはインクリメントされた値で、上記で示したように、メモリアクセスが1つ増えます。

もちろん、単一のi++;ステートメントのようにインクリメントの値が使用されない場合、コンパイラーはポストフィックスやプレフィックスの使用に関係なく、インクリメント命令を生成できます(実際に生成します)。


補足として、が存在する式は、追加の作業(たとえばを追加すること)なしでb++は単純に式に変換できないことを述べておきます。したがって、これらが何らかの式の一部である場合に2つを比較しても、実際には有効ではありません。多くの場合、式の中で使用するとは使用できません。そのため、潜在的に効率がよくても、それは単に間違っているでしょう。もちろん、式が物乞いをしている場合は例外です(たとえば、これをに変更できます)。++b- 1b++++b++ba = b++ + 1;a = ++b;


4

私はここでほとんどの回答と多くのコメントを読んでいますが、どこがより効率的であると考えることができる1つのインスタンスへの参照は見られませんでした(そしておそらく驚くほどより効率的でした)。これは、DEC PDP-11用のCコンパイラ用です。i++++i--i i--

PDP-11には、レジスタの事前デクリメントとポストインクリメントのアセンブリ命令がありましたが、その逆はありませんでした。これらの命令により、「汎用」レジスタをスタックポインタとして使用できました。したがって、そのようなものを使用した場合*(i++)、単一のアセンブリ命令にコンパイルできますが、*(++i)できませんでした。

これは明らかに非常に難解な例ですが、ポストインクリメントがより効率的であるという例外を提供します(または、最近PDP-11 Cコードに対する需要があまりないため、私はと言った方いいでしょう)。


2
非常に難解ですが、非常に興味深いです!
マークハリソン

@daShier。+1、私は同意しませんが、これはそれほど難解ではありません、または少なくともそうであってはなりません。Cは、PDP-11がターゲットプロセッサであった70年代初頭にAT&T Bell LabsでUnixと共同開発されました。この時代のUnixソースコードでは、値が割り当てられたとき「j = i ++」、またはインデックスとして使用されたとき「a [i ++] = n」を開発者が知っていたため、「i ++」が普及しています。コードは少し速くなります(そして小さくなります)。preが必要でない限り、ポストインクリメントを使用する癖がついたようです。他の人たちはコードを読んで学び、この習慣を身につけました。
jimhark

68000は同じ機能を備えており、ポストインクリメントとプレデクリメントはハードウェアで(アドレッシングモードとして)サポートされていますが、その逆はサポートされていません。Motorolaチームは、DEC PDP-11に触発されました。
jimhark

2
@jimharkは、はい、私は68000に移行し、それらのPDP-11プログラマの一つだと、まだ使用--iしてi++
daShier

2

私は常にプリインクリメントを好みますが...

operator ++関数を呼び出す場合でも、関数がインライン化された場合、コンパイラーは一時変数を最適化することができることを指摘しておきたいと思います。operator ++は通常短く、ヘッダーに実装されることが多いため、インライン化される可能性があります。

したがって、実際には、2つのフォームのパフォーマンスに大きな違いはありません。ただし、オプティマイザに頼って判断するよりも、自分が言おうとしていることを直接表現する方が良いように思われるため、常に事前インクリメントを優先します。

また、optmizerの実行を少なくすると、コンパイラーの実行が速くなります。


質問はCに関するものですが、投稿はC ++固有です。いずれにしても、あなたの答えは間違っています。カスタムのポストインクリメント演算子の場合、コンパイラーは一般に効率的なコードを生成できません
Konrad Rudolph、

彼は「関数がインライン化された場合」と述べ、それが彼の推論を正しいものにします。
Blaisorblade、2009年

Cは演算子のオーバーロードを提供しないので、事前の質問と事後の質問の大部分は興味深いものではありません。コンパイラーは、他の未使用のプリミティブに計算された値に適用されるのと同じロジックを使用して、未使用のtempを最適化できます。サンプルについては、選択した回答を参照してください。

0

私のCは少し錆びているので、お詫びします。Speedwise、私は結果を理解することができます。しかし、両方のファイルがどのように同じMD5ハッシュに出力されたかについて、私は混乱しています。多分forループは同じように実行されますが、次の2行のコードは異なるアセンブリを生成しませんか?

myArray[i++] = "hello";

myArray[++i] = "hello";

最初のものは配列に値を書き込み、次にiをインクリメントします。2番目のインクリメントは、配列に書き込みます。私はアセンブリの専門家ではありませんが、これらの2つの異なるコード行によって同じ実行可能ファイルがどのように生成されるかはわかりません。

ちょうど私の2セント。


1
@Jason Zコンパイラの最適化は、アセンブリの生成が完了する前に行われ、i変数が同じ行の他の場所で使用されていないことがわかるため、その値を保持することは無駄であり、おそらく効果的にi ++に切り替えます。しかし、それは推測にすぎません。講師の1人がより速いと言って、実用的な証拠で理論を修正する人になるまで待ちきれません。私はすでに敵意を感じることができます^ _ ^
Tarks

3
「私のCは少し錆びているので、お詫びします。」Cに問題はありませんが、元の質問を完全には読んでいません。「結果の値を使用しない場合、 i ++と++ iの間にパフォーマンスの違いはありますか?」斜体に注意してください。あなたの例では、i ++ / ++ iの「結果」使用されていますが、慣用的なforループでは、pre / postincrement演算子の「結果」は使用されていないため、コンパイラーは好きなことを実行できます。
Roddy、

2
あなたの例では、値を使用しているため、コードは異なります。それらが同じである例は、増分に++のみを使用しており、どちらからも返された値を使用していませんでした。
John Gardner、

1
修正:「コンパイラーはi ++の戻り値が使用されていないことを確認するため、++ iにフリップします。」同じ行(ステートメント)にi ++、i ++のいずれかと一緒にiを含めることができないため、書き込んだ内容も間違っています。その結果は未定義です。
Blaisorblade、2009年

1
何も変更foo[i++]foo[++i]ずにに変更すると、プログラムのセマンティクスが明らかに変更されますが、一部のプロセッサでは、ループホイスト最適化ロジックなしでコンパイラを使用する場合、インクリメントpしてq1回実行すると、たとえば、を実行するループを*(p++)=*(q++);使用するよりも高速になります*(++pp)=*(++q);。一部のプロセッサでの非常にタイトなループの場合、速度の差は大きく(10%以上)なる可能性がありますが、Cでポストインクリメントがプリインクリメントよりも実質的に速い唯一のケースです。
スーパーキャット2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.