• ベストアンサー

なぜ、i++なのか?(ものすごくくだらない質問です)

C言語や、それに文法が似ている言語では、 for(i=0; i<10; i++)... のような例をよく見かけます。 ここで、何故か++iよりi++を使うほうを非常によく見かけるのですが、何故なんでしょうか? 単独で使う分にはどちらでも同じなので、実際はどうでもいいのですが。 個人的には、++iは副作用がまずあって、その副作用の結果を返すのに対し、i++は副作用があることは同じですが、「副作用を起こす前の値」を返す演算ということで、i++の方が少々不自然な感じがしますので、++iの方が好きなのですが。 もし、何か特別な理由があることを知ってらっしゃる方がいたらお願いいたします。

質問者が選んだベストアンサー

  • ベストアンサー
  • aris-wiz
  • ベストアンサー率38% (96/252)
回答No.9

C言語の規格書内の例やfor文の説明で、 i++という表現が使用されており、 多くのC言語を教えている書籍や 先人の方々によってそれが伝統的な書き方に なっているからではないでしょうか? 極端な話、変数名だってiである必要もありませんし。。。 また、効率を気にして++iなどにされる方も多いと思いますが、 あくまでも理論上であって、inc命令の使える最近のCPUでは 処理に差が出ないから「よく使われているi++を使う」という人も いると思います。 >++i は処理前、i++ は処理後です。なので処理文中に使うと > 値が違ってきます。 確かにそうですが、for文の(初期化節・条件式・ボイド式)に ついてはループに入る前に評価され、それぞれの節、式に 副作用完了点があるため、前方置換・後方置換どちらで書いても 単項式であるなら、結果は変わりませんしボイド式の中で、 計算順序を気にしなければならない様な複雑な処理を書くべきでは 無いと思います。

noname#130082
質問者

お礼

回答ありがとうございます。 まさか、こんな沢山回答をいただけるとは・・・。 教科書などの書籍の影響ですか。確かにそれも大きいですよね。 昔の教科書とか、確かめてみなければ・・・。 C言語でなくとも、言語の入門書の最初のサンプルが Hellow World になってたり(^^;。 C++言語という名前も、i++の書き方の方が多かったからかもしれませんし。 効率を考えすぎて読みにくいプログラムを作るよりは、CPUや最適化にまかせた方がいいかもしれませんね。 私の質問も、あくまで、前置と後置のどちらでもよい場合に、何故後置が多用されるのか?ということです。 ボイド式以外でも、できるだけ計算順序を勘定に入れなければいけないような記述は避けたほうがいいですよね。私も、インクリメントやデクリメントは式中でなく、出来る限り単独で使う方針です。これは、副作用のある関数を式中に使う場合も同様の注意が必要ですね。

noname#130082
質問者

補足

うわぁ! 何と、K&R「プログラミング言語C」がi++を使ってました。 何とか手に入れたのが古本の「第2版のANSI規格準拠版」なので、はっきりとはわかりませんが、初版でも多分同じなのではないかと思います。 この本によりますと、最初は++iを使ってますが、第2章8節で前置++、--と後置の意味の違いを明記した後は、何故か基本的にi++を使っています。まだ全部を熟読したわけではないのですが、取りあえずこの時点では、何故そうするかの説明は無いようです。 多分、合理的な理由はあるのでしょうが、それとは別に「K&Rでi++を使っているから、たぶんこれが正しいやり方なのだろう」と思って後置の方を使ったプログラマが沢山いたことは間違いないと思います(^^;;;;。 ここらへんが多分正しそうな気がします(^^; K&Rが何故後置を使ったのか?は別質問になりますので、どうしても分からなければ別質問をするとします。取りあえず、考えられることは。 ・K&Rの使っていたコンピュータがi++の方が都合が良かった。 ・while(*s++ = *t++); のようなトリッキーだが便利な機能がCで書けるので、後置を使うことにした(C言語を売り出すためには、Fortran、Cobol、Pascalなどの既存の言語との差別化が必要だった)。 ・後置を使うと for(i ~;i ~;i ~)... という形になって形が綺麗である。 あたりが考えられます。 あと、C++ では 演算子のオーバーロードができるために事情が違うわけです。C++ の場合は後置++の方がほとんどの場合効率が悪いので、後置を使う特別の理由がない限りは前置の方を使うのが正しい、わけです。 ところで、#6さんへの回答への補足に間違いがあったのですが、#6さんが突っ込んでくれないので、自分の間違いの指摘をここでさせていただきます(__)。 Javaではクラスのインスタンスを作るときはnewを使うので勘違いしてしまいました。C++ で後置++を定義するときは、newは使わずに局所変数に自分のコピーを作って、それをreturnするのが正式のやり方なんですね。従って、C++;と単独で使った場合には、returnした後に自動的にインスタンスは破棄されるのでメモリリークは発生しない、わけです。 そのかわり、 A=C++; というようなことをやると、まずCの中のauto変数に自分自身のコピーを作ってそれを返すが、auto変数のインスタンスは消えてしまうので、Aはあらためてクラスのインスタンスを作って生成しなければいけない。つまり、自分自身のコピーを作る、という操作が「2回」必要になるわけです。で、Aのインスタンスもいずれは破棄しなければいけないので、破棄も結局は「2回」やらなければいけないわけですね。確かにこれは効率が悪い(^^;;;;; まあ、私はC++の文法もよく知らないし、C++のプログラムを作ったことは1度もないので、この間違いはご容赦ください(__)。 javaでは、そもそも++の再定義ができないし、newはあってもdeleteはないので「悩む必要がない」わけです。 なるほど。「自由には責任が伴う」ので、javaでは「自由を制限することで、責任も減らす」ためにC++より厳しい規則になっていて、そのかわりC++より悩みを少なくしているわけです(^^; 大分、仕組みが分かってきました(^^)。 結局、質問したことは無駄ではなかったわけです。勉強になりましたから(^^)。 ということで、大体分かったので、何か見落としていることがあって、誰かが突っ込んでくれる可能性があるのでしばらく締め切りは待つことにします。しばらくたっても突っ込みがなければ質問を締め切らせていただきます。

すると、全ての回答が全文表示されます。

その他の回答 (11)

  • kiwa67
  • ベストアンサー率22% (82/357)
回答No.12

#1です。 > 取りあえず、C言語の規格を確認しないと・・・。 規格では、   (*(p++)) に統一されているはずですが、全てのコンパイラが規格どおりとは、限らないということです。

noname#130082
質問者

お礼

補足、ありがとうございました。 そういう意味でしたか。 規格を間違えて覚えてしまったのかと、あわててしまいました。 *p++ を (*p)++ と解釈されるのは困りますねえ。 それでは、++や--の問題というより、 *p++ のような構文的に混乱の可能性のある式は、冗長でも括弧を使って *(p++) と明示した方がよさそうですね。 ありがとうございました。

すると、全ての回答が全文表示されます。
  • kiwa67
  • ベストアンサー率22% (82/357)
回答No.11

#1 です。 > 個人的な意見ですが好みで++i,i++を使うのは止めた方が > いいです。 > ポインタ処理のアドレス移動とかでバグを生む可能性が高いです。 この件に関して過去の実例として、ポインタ p に対して   *p++ が、処理系によって解釈が違うケースに遭遇しました。 ある処理系では、   *(p++) と解釈されたり、別の処理系では、   (*p)++ と解釈されたり。。。。 移植性を考えた場合、ポインタに ++ は使うべきではないね。 と実感しました。

noname#130082
質問者

お礼

本当ですか? 今の今まで、C言語では、後置演算子は前置演算子より結合が強いとばかり思っていたので。 急いで適当に検索してみましたが、 http://www.grapecity.com/japan/powernews/column/clang/021/page03.htm で、 char *p; のときに while(*p++)... という書き方をしていますが、明らかに「構文解析」では while(*(p++))... と解釈し、「実行順序では」whileの条件判断では最初の *p が使われ、その後に、pがインクリメントされていますけどねえ。 取りあえず、C言語の規格を確認しないと・・・。 いろいろ勉強になります。ありがとうございました。(いろいろな勉強に時間がかかりそうなので締め切りは遅くなりそうです)。

すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.10

C++ でインクリメント/デクリメント演算子を使うようになると ++i を好きになれるかもしれない>#9. 後置の方が, 明らかに処理量が多いんですよね. ついでにいうと前置と後置の根本的な違いは「その演算によって得られる値」だけであり, 「インクリメントするタイミング」ではありません>#7. つまり printf("%d\n", ++i); を printf("%d\n", i+1), i=i+1; と解釈しても全く問題ありませんし逆に printf("%d\n", i++); を i=i+1, printf("%d\n", i-1); と解釈しても構わない. というか, (C/C++ では) 「いつインクリメントされるか」に依存してはならないことになってる.

noname#130082
質問者

お礼

ご回答ありがとうございます! 勉強しなければならないことが、どんどん増えてきます(^^;。 C++ で ++、-- をやると、前置の方が好きになるかも、ですか。 それでは、++C 言語とするべきだったかもしれませんね(^^;。 後置だと、「元の値」を覚えていなければならないので処理は増えますよねえ。そこらへんも不自然さを感じていたのです。 >「いつインクリメントされるか」に依存してはならないことになってる めもめも。また勉強になりました<(__)>。

noname#130082
質問者

補足

検索してみると、C++では違いが大きいということになってますね。 http://d.hatena.ne.jp/cubicdaiya/20080606/1212695409 http://z56.blog.so-net.ne.jp/2008-07-21 後置の場合、元の値を覚えていなければならない、ということは、オブジェクトを生成・破棄しなければならなくなるわけですね。 取りあえず、C++をやることになったら、気をつけます。 ありがとうございました。

すると、全ての回答が全文表示されます。
  • tadys
  • ベストアンサー率40% (856/2135)
回答No.8

CPUによっては機械語の命令の中に「ポストインクリメント命令」と「プリディクリメント命令というものを持ったものがありこのCPUを使う時は *i++ は1命令で実行が出来るが *++i は2命令が必要、 *--i は1命令で実行が出来るが *i-- は2命令が必要、 という風になります。 そのため *++i を繰り返し実行する場合には 実行速度を上げるために *i++ に置き換えることがあります。 ++i と i++ では速度に差は出ないのですが * が付く場合には ++i と i++ に差が出てきます。 こういうCPUが多かったためインクリメントする時は i++ を使う事が習慣になったと思われます。

noname#130082
質問者

お礼

回答、ありがとうございます! へえ、「ポストインクリメント命令」と「プリディクリメント命令」なんてものがあったんですか! 知りませんでした(。_。; (また、つまらん無知を晒してしまった・・・。) そういう事情もあったんですね。勉強になりました<(__)>。 まあ、インクリメント・デクリメントにポインタが絡んでくるとやっかいですね。頭が痛くなります。 CPUの違いは、できればコンパイラの方で吸収してくれると助かるのですが、なかなか世の中甘くないですね。

すると、全ての回答が全文表示されます。
noname#88772
noname#88772
回答No.7

 こんにちは。  なかなか深い質問です。通常はそのまま何も考えずに使ってしまう ことが多いです。  個人的な意見ですが好みで++i,i++を使うのは止めた方がいいです。 ポインタ処理のアドレス移動とかでバグを生む可能性が高いです。  ++i、i++ の根本的な違いは、埋め込んだその処理文内でインクリメント するタイミングです。 ++i は処理前、i++ は処理後です。なので処理文中に使うと値が違ってきます。  以下のプログラムで確認できると思います。i はあえてカウンタとして 使用していません。printf() が一つの処理と考えてください。 i の値が違っているのが解ると思います。  ご参考までに。 ------ ここから ------ #include <stdio.h> int main( void ) { int count, i; printf("--- 1 ---\n"); i=0; // i を初期化 for( count=0; count<10; count++ ) { printf( " [1] i : %d\n", i++ ); } printf("--- 2 ---\n"); i=0; // i を初期化 for( count=0; count<10; count++ ) { printf( " [2] i : %d\n", ++i ); } return 0; } ------ ここまで ------

noname#130082
質問者

お礼

丁寧な回答、ありがとうございました。 まあ、私が「好み」と言ったのは、あくまで、どちらを使っても結果が変わらない場合での話ですので、結果が違ってくるときは当然正しい使い方にする、という意味です(^^;。 もっとも、世の中がi++に慣れているなら、こちらの意地を通す意味もないんで大勢に従う方がいいとは思います。 私も式や関数の引数にインクリメントやデクリメントをする場合は注意が必要だと思います。for文の中でも、i++の部分がもっと複雑な場合は要注意ですし。 私はもう何年もプログラムしてませんが、たぶん私の場合は(自分が後で読むときを考えて)効率より読みやすさを優先して、i++は単独で使うと思います。例えば、yuji_syamiさんの例で言えば、 printf( " [1] i : %d\n", i++ ); は、 printf( " [1] i : %d\n", i ); i++; と書いて、 printf( " [2] i : %d\n", ++i ); は、 i++; printf( " [2] i : %d\n", i ); と書くと思います。これらの場合は前置でも大丈夫ですね。

すると、全ての回答が全文表示されます。
  • BLK314
  • ベストアンサー率55% (84/152)
回答No.6

ymmasayanさんは勘違いされていると思われます http://ja.wikipedia.org/wiki/For%E6%96%87 を参照してください カウンタの更新が行われるのは ループ内の文を実行した後です。 初期条件には何ら影響を与えません。 従って ++iとi++で始まる数が変わるなんてことはありません int _tmain(int argc, _TCHAR* argv[]) { for (int i = 0; i < 10; ++i) { printf("i = %d\n", i); } for (int j = 0; j < 10; j++) { printf("j = %d\n", j); } return 0; } 上記プログラムを実行しましたが iもjもともに0 から 9で同じです 本題に戻りますが 私も以前は i++派でした。 hidebunさん同様、日本語で考えていたからです。 しかし STLを使うようになり 自分で ++の前置, 後置を書くようになってから ++iに改めました。効率が悪いことに築いたからです。 まあ、きっかけは、"Effective C++"なのですが(笑) 実際にコーディングしてみるとより実感できます。 ま、intなどをカウンタにしている場合はほとんど変わらないので どっちでもいいともいえます。 ただ、クラスになると、(BOX化など)話は別で できるだけ効率に気を配ったほうが良いと考えます。

noname#130082
質問者

お礼

ご回答ありがとうございます。 まさか、こんな質問に、こんなに回答が付くとは思っても見ませんでした(^^;。 C++は扱ったことがないので(領域管理とか、多重継承とか、オーバーロードとかが辛そうだった)、これから勉強しないとBLK314さんの回答の意味をきちんと理解するのは難しいですけど・・・。STLの名前は知ってるんですが中身は知らなくて<(__)>。C++は演算子のオーバーロードができるんでしたね。 もっとも、C言語の範囲でも、++i と i++ の働きをする関数を作ろうとすると、i++ の方が処理が余計にかかりそうですね。それがクラスとなれば、確かに効率の差は大きいかもしれません。

noname#130082
質問者

補足

私がC++を誤解していなければの話ですが。 CFooというクラスで、前置++と後置++が定義されている場合、前置++ではコピーは必要ないが、後置++では多分、自分自身をコピーしてから、何らかのインクリメント処理をするわけですね。とすると、CFoo型へのポインタを扱う場合、前置と後置ではインスタンスが同じか違うか、という差が出るわけですね。 というより、 CFoo x(・・・); の場合、 ++x; はともかく、単独の x++; は、以前のxのコピーが破棄されずに残って、もろにメモリリークを引き起こすのでしょうかね。 C言語だと単独で使う分には前置++も後置++も結果は同じになりますけど、C++ のクラスでは結果はおそらく違うことになりますね。 その場合だと、好みの問題ではなくなりますね。

すると、全ての回答が全文表示されます。
  • asuncion
  • ベストアンサー率33% (2127/6290)
回答No.5

>#4さん >i++なら0から処理開始 >++iなら1から処理開始です。 おっしゃっている意味が全くわかりません。 詳しいご説明をお願いいたします。

noname#130082
質問者

お礼

コメント、ありがとうございます。 #4さんのコメントがなかなかないようですので、想像ですが、私の私見を述べさせていただきます。 #4さんは「++i」は「まずiをインクリメントする」という意味で、「i++」は「後からiをインクリメントする」ととらえていたために、勘違いをなさっていたのではないかと想像します。 しかし、こういうことは、前置++と後置++がある以上、必ず勘違いをされる方が出てくる、ことはほとんど確実と思われます。 私の疑問も、こういう勘違いは必ず出てくるので、後置++のようなものを使うのはいいのだろうか?という疑問も含まれているのです。 結局、私の私見では、前置と後置の++、--の両方があるのは、勘違いをほとんど必ず引き起こすので、片方に統一した方がいいのではないか?という結論に傾いています。

すると、全ての回答が全文表示されます。
  • ymmasayan
  • ベストアンサー率30% (2593/8599)
回答No.4

初期値i=0との絡みだと思います。 i++なら0から処理開始 ++iなら1から処理開始です。 私は前者のほうが勘違いしにくいような気が。 逆に終了条件は要注意ですが。

noname#130082
質問者

お礼

回答、ありがとうございます。 しかし、大変失礼ですが、この私の質問の形ではどちらも同じ結果になるはずだと思いますけど。 ++iは確かに「先にiを増加させる」ものですが、終了判定やfor文のbodyより先ではなかったと思います。 もっとも、どちらにしても繰り返しは、初期値の設定間違いと終了判定の間違いがバグの温床であることには間違いはないですね(^^)。注意してしすぎることはないでしょう(^^)。 私もより注意が必要だという確認になりました。 ありがとうございます<(__)>。

すると、全ての回答が全文表示されます。
  • hidebun
  • ベストアンサー率50% (92/181)
回答No.3

日本語の語順で考えながらコードを書くからじゃないですか? 「増やす(++)iを」よりも、「iを増やす(++)」と考えるほうがしっくりくる。 ソースコードを眺めているときに、心の中で、音読したりしませんか? 英語圏の人は、どう書くんでしょうね。

noname#130082
質問者

お礼

日本語ってのは考えませんでした。確かに、日本語は後置記法の方が合っているとは前から思ってはいましたが。 しかし、C++ と言う名前は日本人じゃないような・・・。 どちらにしても、日本人にとっては後置の方が見やすそうですね。 ありがとうございました。

すると、全ての回答が全文表示されます。
  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.2

見やすいから, でしょうね. 理論上は ++i の方が速くなる可能性があるんですが.

noname#130082
質問者

お礼

回答ありがとうございます(^^)。 やはり、見やすさ、という方が多いですね。 速さに関しては、確かに機械語にはインクリメント命令があるわけだから++iは使い場所によっては非常にはやくなりますね。まあ、コンパイラの最適化でそれほど大きな差が出ないかもしれませんが。 とはいえ、共同でプログラムを作ったり、何度も「バージョンアップ」をしなければならないソフトの世界では、見やすさもはやさのうちかもしれませんね。

すると、全ての回答が全文表示されます。

関連するQ&A