- ベストアンサー
インクリメント演算子でのオブジェクト(変数)を評価する時期
インクリメント演算子について以下のような例題を考えてみました。 #include<stdio.h> int main(void) { int at=0; if(at++) printf("True at=%d\n",at); else printf("False at=%d\n",at); return 0; } この時答えとしては Falsue at=1です。 これは、if文の制御式( )で at=0と判定しそのごat=1となるため、else文以降が実施されるためです。 atはメモリ上に配置されると思いますが、どの時点までat=0であり、どの時点でat=1になると考えたら良いのでしょうか。 アセンブリの問題になると思いますが、宜しく願います。
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
値を評価するまでは0、評価した後は1です。 at=at++;とすると、atの値は変化しません。 想定されるif文の翻訳(80386と仮定)は以下の通り MOV EAX,at ;変数からレジスタにデータを転送 INC at ;変数をインクリメント OR EAX,EAX ;インクリメント前の変数の内容を評価 JZ @xxx ;ゼロならばELSE節へ分岐 == 以下THEN節の処理 インクリメントによってフラグが変化してしまうので、以前の値を 記録しておき、インクリメント後に評価しています。冗長にやるなら CMP at,0 ;変数と0を比較する PUSHF ;フラグを退避 INC at ;変数をインクリメント POPF ;フラグを復旧 JZ @xxx ;ゼロならばELSE節へ分岐 == 以下THEN節の処理 実際に調べるには以下の通りです。 int at=0, wk; if(( at++ )||( wk = at )) { //★ = は1個だけ(= =ではない) printf("True at=%d, wk=%d\n", at, wk); } else { printf("False at=%d, wk=%d\n", at, wk); } 結果は "True at=1,wk=1"です。 if文の2番目の式(wk←at、wk≠0)の評価時点で、インクリメント済みに なっています。
その他の回答 (8)
- 麻野 なぎ(@AsanoNagi)
- ベストアンサー率45% (763/1670)
これは、「作用」と「評価」の混同から起こる混乱です。 解説書などには、 at++ は、「at の現在の値を評価した後、at をインクリメントする」 ++a は、「at をインクリメントした後 at の値を使う」という書き方がされている場合がありますが、これは、必ずしも正しくありません。 実は、「評価(式の値を決定する)」のと「作用を行う(インクリメントする)」というのは、独立したものです。 ですから、 at++ は、「その式が完了するまでに(というのが、つまり、「副作用完了点までに」という意味) at をインクリメントする」「式の値としては、インクリメントする前の at の値を採用する」 ++at は、「その式が完了するまでに at をインクリメントする」「式の値としては、インクリメントした後の at の値を採用する」 です。ですから、実際の at の値がいつか割るかには全く関係なく、 at++ という式の値は、インクリメントする前の at の値になるということです。 また、 at = at = at; という式ですが、 = というのは、2項演算子に分類されます。(しかも、結合順序は右から左) 従って、この式は、 at = (at = at); という式になります。 a = b = c = 0; というのは、見た目、「a と b と c に 0 を代入する」に見えますが、実際の規定は、 c に 0 を代入する。式全体( c = 0 )としての値は、 0 次に、その結果(つまり、0)を b に代入する( b = (c = 0) )この式としての値は 0 最後に、a にこの結果を代入する( a = (b = (c = 0)) )この式としての値は 0 という意味合いになります。
- Tacosan
- ベストアンサー率23% (3656/15482)
ついでにいえば at = at = at; も (at の値を 2度「変更」しているので) 未定義動作です. しかし at = (at = at) ? at : at; は問題なし.
- titokani
- ベストアンサー率19% (341/1726)
訂正 at=at++; これは「未定義」でした。
- titokani
- ベストアンサー率19% (341/1726)
ちなみに、 at=at++; は、副作用完了点(;)までに2回値が変わるので、結果は「不定」 if((at++)|at) これはNG。副作用完了点の前にatを参照するから。 if((at++)||at) これはOK、||は副作用完了点であるから。 で、いいと思う・・・。
- titokani
- ベストアンサー率19% (341/1726)
言語仕様で定義されています。 「副作用完了点」で検索すると、いろいろ出てきます。 この場合は、ifの()が閉じた時点。
- nda23
- ベストアンサー率54% (777/1416)
++、--はもともとPDP11系のアセンブラにあった書式です。 at = at++; は言語仕様上、全く問題ありません。 at = at = at; とか if(( at++ )||at) はやる人はいませんが、 問題なく実行可能です。 尚、最適化の度合いによっては更新時期が微妙に違うことが あります。20年くらい前のMSCにはこのバグがあって、苦労しました。
- rinkun
- ベストアンサー率44% (706/1571)
アセンブリの問題じゃなく言語仕様の問題でしょう。 at++式の値は0だけど、式の評価が終わった後ではat==1になっている。 ちなみに at=at++; は二重代入になって言語仕様的にはダメなはず。 # エラーか未定義か実装依存かはしらない if((at++)|at) とか if((at++)||at) とか も拙いんじゃないかと思う。
- precog
- ベストアンサー率22% (966/4314)
elseにjumpする前に+1されてると思います。そのほうがキャッシュが乱れないと思うので。 依存関係がないと判断されて、+1されないかもしれませんけど。(コンパイラ次第?) 論理的にはelseに入ったらもう+1されてるハズです。
補足
>at=at++;とすると、atの値は変化しません。 の意味が解りません。 int at=0 at=at++; としたとき at=1に変わっているはずですが。 宜しく願います。