i=i+1,i+=1,++i,i++の違い

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Revell

i=i+1,i+=1,++i,i++の違い

#1

投稿記事 by Revell » 15年前

こんにちは。

最近すごく気になっているのですが、
i=i+1;
i+=1;
++i;
i++;
上の4つのステートメントの中で処理速度が一番速いものは一体どれなのでしょうか?

for文内などでカウンタとして使用する場合、多くのCやC++の書籍ではi++という後置型が用いられているようですが、i++が一番処理効率がよいということなのでしょうか。

少し調べてみますと、CPUによってはマシン語の命令の中に前置型か後置型の一方が設けられていることがあるので(インクリメントの場合は後置型)、i++を用いた方がよいというようなことが書いてありました。

僕の考えとしてはコンパイラによって最適化される際に全部同じように解釈されるのかな、という感じです。

状況としては、iは整数型で、単純に整数定数の1を加算するだけの処理についてです。
また、言語はCとC++、両方の場合について教えてほしいです。
ご回答よろしくお願いします。

y

Re:i=i+1,i+=1,++i,i++の違い

#2

投稿記事 by y » 15年前

コンパイラの最適化によっては、いずれも殆ど同じなります。
ただし後置きインクリメントは一時変数を作るので、基本的に遅いです(コンパイラ依存)。

前置きは、単純にi+=1をしていますが、
後置きは、一旦値をどこかに退避させて、それからi+=1してから、退避させた値を返します。

といっても、潤沢な環境に於いては微々たる違いだと思います。

ムンバ

Re:i=i+1,i+=1,++i,i++の違い

#3

投稿記事 by ムンバ » 15年前

こんばんは。

>>i=i+1;
>>i+=1;
>>++i;
>>i++;

同じ条件で、各速度を計るソース(ファイル)を4種類作ってみて
各ファイルで、それぞれ何度も計測してみては如何でしょうか?

Revell

Re:i=i+1,i+=1,++i,i++の違い

#4

投稿記事 by Revell » 15年前

>>yさん
ご回答ありがとうございます。
では、
i=i+1,i+=1,++i
この3つはすべて同じ処理過程を踏む、ということでよろしいでしょうか。

また、CとC++は特に区別する必要なく、両言語とも内部処理は同じだということでしょうか。

>潤沢な環境に於いては微々たる違いだと思います
そうですね。実際にこのような加算の速度がプログラム全体の実行効率に影響を及ぼすようなことはまずないでしょうが、ふと気になった次第です。


>>ムンバさん
ご回答ありがとうございます。
そうですね。実はそれはもうやってみたのですが、計測のたびに結果が異なるので、おそらく数ミリ秒単位では計れないほどに微々たる差なのではないかと思います。
精密な測定環境でもあれば話は別ですが、マルチタスク処理を行っているWindowsでは無理なのかなと思いました。
また、計測時間を膨大に取れば可能でしょうが、そこまでするよりも理論を知ったほうが早いと思い、質問させていただいた次第です。

組木紙織

Re:i=i+1,i+=1,++i,i++の違い

#5

投稿記事 by 組木紙織 » 15年前

i=i+1;とi+=1;は規格上は同じとみなしたはずなので、計算速度に違いはないかと思います。
i+=1;と++i;は規格上同じとみなしたがどうか覚えていませんが、同じ動作だと思います。
yさんが言ってるのも考えると、
i=i+1;とi+=1;と++i;は同じ速度で、i++;だけが少し遅くなると思います。

今回の場合単純な場合は最適化されて違いは出てこないとおもいます。



実際にアセンブラを見てみると(Debugモードで)
今回のようなすべて単独で使われる場合だとすべて同じのが出力されたので、
速度に違いは一切ないです。
Releaseモードだと
int i=5;
と同等のアセンブラに最適化されてしまったので今回は考えていません。
#何時も思うけど最適化ってすごいですね。

環境VS2005,OS:Vista

//ソースプログラム
#include <iostream>
int main()
{
int i=1;
i=i+1;
i+=1;
i++;
++i;
std::cout << i<< std::endl;
return 0;
};
//出力されたアセンブラの一部
_main PROC ; COMDAT

; 4 : {

push ebp
mov ebp, esp
sub esp, 204 ; 000000ccH
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-204]
mov ecx, 51 ; 00000033H
mov eax, -858993460 ; ccccccccH
rep stosd

; 5 : int i=1;

mov DWORD PTR _i$[ebp], 1

; 6 : i=i+1;

mov eax, DWORD PTR _i$[ebp]
add eax, 1
mov DWORD PTR _i$[ebp], eax

; 7 : i+=1;

mov eax, DWORD PTR _i$[ebp]
add eax, 1
mov DWORD PTR _i$[ebp], eax

; 8 : i++;

mov eax, DWORD PTR _i$[ebp]
add eax, 1
mov DWORD PTR _i$[ebp], eax

; 9 : ++i;

mov eax, DWORD PTR _i$[ebp]
add eax, 1
mov DWORD PTR _i$[ebp], eax

たかぎ

Re:i=i+1,i+=1,++i,i++の違い

#6

投稿記事 by たかぎ » 15年前

CINTのようなインタープリタ環境まで考えるなら、おそらく ++i が最も高速になるかと思います。
インタープリタでは実行時にソースの字面を解釈するので、構成する文字数が最も少なく、構文木が最も単純になるのが ++i だからです。

整数型以外、例えば反復子を考えるのであれば、やはり ++i が最も高速になります。
一時オブジェクトが生成されることがないのと、仮引数が最も少ないことが理由です。

Revell

Re:i=i+1,i+=1,++i,i++の違い

#7

投稿記事 by Revell » 15年前

>>組木紙織さん
ご回答ありがとうございます。
アセンブリレベルで解析すれば確かに同じだということが見て取れました。
iは整数型として単純にカウンタとして用いるような場合は違いはない、ということですね(コンパイラがVS2005の場合)。
組木紙織さんが試された言語はC++のようだったので、僕はCで同様にアセンブリコードを出力させたところ、4つのステートメントは全て同じように翻訳されていました。

参考になりました。
ありがとうございました。


>>たかぎさん
ご回答ありがとうございます。
インタプリタ環境では++iが最も高速になるかもしれないということですね。
参考にさせてもらいます。

C++で反復子を用いる際は前置型を使用したほうがよいということですね。
反復子を用いる場合は意識してみたいと思います。
参考になりました。
ありがとうございました。


ご回答くださったみなさん、ありがとうございました。
解決しました。

閉鎖

“C言語何でも質問掲示板” へ戻る