演算子の優先順位が よりも高いのに、 が最初に++x || ++y && ++z
計算されるのはなぜですか?++x
&&
||
11 に答える
は?
&&
よりも強くバインドすると言っている場合||
(これは true です)、式は次のようになります。
++x || (++y && ++z)
||
短絡なので、最初に左側を評価する必要があります。
あなたがそれが同等であるべきだということを意味するなら
(++x || ++y) && ++z
&&
も短絡するため、同じことが当てはまります。つまり、||
最初に を評価する必要があり、その結果++x
、最初に評価するものになります。
&&
は よりも優先順位が高いため||
、式が次と同等であることを意味します。
++x || (++y && ++z)
したがって、プログラムが の結果の評価を開始する前に、の右側のオペランドを&&
評価する必要があるかどうかを判断するために評価する必要があります (論理二項演算子は「ショートサーキット」であり、右側を評価しないことを意味します)。左辺が結果を決定するのに十分である場合)。ここには怪しいものやコンパイラ固有のものはありません。この式の動作は、C 標準によって正確に指定されており、どのコンパイラでも同じです。、、およびがすべて同じ変数である場合でも機能します。++x
||
x
y
z
||
&&
Unwind、Rなどは、実際に何が起こるかを説明しています。だから私はちょうど追加させてください:
ご質問の前提が間違っています。の優先順位が高いという事実は、&&
それを囲むオペランドが優先順位の低い式のオペランドよりも前に評価されなければならないという意味ではありません。||
とthisの特殊なケースの短絡でさえ、&&
必ずしもそうであるとは限りません。
たとえば、次のように考えてa=b+c+d*e
ください。*
は よりも優先されますが、それは の前に評価する必要がある+
という意味ではありません。これは、製品を式全体に追加する前に評価する必要があることを意味します。コンパイラは、この式を,として評価することも、,として評価することもできます。どちらも同じように有効です。d*e
b+c
temp1=d*e
temp2=b+c
a=temp1+temp2
temp1=b+c
temp2=d*e
a=temp1+temp2
と のショートサーキット動作では||
、&&
評価の順序にいくつかの追加の制限があります。
補足として: 一般的に、このようなコードを書くことは避けます。このコードを読もうとしている別のプログラマーが、インクリメントがいつ発生し、いつ発生しないかについて混乱しているのを簡単に見ることができます。まあ、実際の変数名を使用した場合、それほど奇妙に見えないかもしれません。
私は時折、副作用を防ぐために短絡に頼っています。お気に入り
if (!eof() && readNextInt()>0)
すでにファイルの終わりに達している場合、読み取りを防ぐために短絡に依存しています。または
if (confirmDelete==YES && deleteEntry()!=-1)
最初のテストで false を短絡することに依存しているので、削除すべきでないときに削除を行いません。しかし、これらの例は私には非常に簡単に思えます。有能なプログラマーであれば、私が何をしているかを理解してくれることを願っています。しかし、例がわかりにくい場合は、分解する必要があると思います。検討
if (customerType==RETAIL || lastDepositAmount()>100.00)
lastDepositAmount()
副作用があった場合、小売りである場合、customerType
この副作用は決して起こりません。それが必ずしも読者にとって明白であるとは思いません。(関数名が、データを取得していて更新を実行していないことを暗示していることと、顧客の種類と預金額の間に明らかな関係がないことが理由の 1 つです。これらは 2 つの独立したもののように聞こえます。) 確かに、これは主観的。しかし、疑わしい場合は、ささいなパフォーマンスの向上よりも単純さと明快さを選択してください。「これはあいまいな機能のクールな使い方です。これを読んでいる人なら誰でも、これを行うのに十分なほど言語を理解するには、私がどれほど賢くなければならないかに感銘を受けるでしょう」 .
ここにはひどく間違った答えがあります。
この式の評価の順序は、実装に依存しません。明確に定義されています!
&&
より高くバインドするため、||
この式は。と同等++x || (++y && ++z)
です。さらに、とは両方とも&&
短絡||
しているため、式の左辺で値を決定するのに十分な場合、右辺は評価されません。
これはいつですか?ええと、特に単一の値ではなく複雑な式であっても、の値に関係なく、False && a
常にに解決されることを私たちは知っています。したがって、私たちはまったく評価しません。同様に、常にに解決されます。False
a
a
a
True || a
True
これにより、この例では非常に明確な評価順序が得られます。最初 ++x
に、次に(ある場合)++y
、次に(再び:ある場合)++z
。
演算子は、図に示すように、Polish ツリー データ構造を使用して評価されます。これは、深さ優先の評価アルゴリズムです。演算に名前を付けましょう: A = ++x B = ++y C = ++z D = B && C E = C || D 評価順序: A、B、C、D、E。もちろん、C には最適化があり、A が true の場合、E は BC と D を評価せずに true として評価されます。同様に、B が false の場合、C が勝ちました。評価速度を最適化するために評価されません。
++ は、プレインクリメントとして、すべての中で最も優先度が高いです。これは、この演算の結果の値が二項演算子に渡されることを意味します。ただし、興味深いのは、++x の短絡が残りの部分と or'ed になっていることです。++x が true の場合、残りはまったく実行されない可能性があります。
特にこの場合、評価の優先順位と順序は同じではありません。すべての優先順位は、式を次のように解析する必要があることを示しています。
++x || (++y && ++z)
IOW、それは一緒に OR されている式が and であることを意味し++x
ます(++y && ++z)
。が前に評価されるという意味ではありません。(++y && ++z)
++x
論理演算子||
and&&
の場合、評価は常に左から右です (オンライン C 標準、セクション 6.5.13 および 6.5.14)。どんな表現にも
a || b
a
完全に評価されます。の結果が 0b
でない限り評価されません( の代役との代役を考えてください)。同様に、任意の式についてa
a
++x
b
++y && ++z
a && b
a
完全に評価されます。b
の結果が 0 でない限り、評価されませa
ん。
したがって、あなたの場合、式++x
が最初に評価されます。結果が 0 の場合のみ++y && ++z
評価されます 。
||
および&&
は、評価の順序が左から右であることが保証されているという点で特別です。これは、ビット演算子または算術演算子には当てはまりません。たとえば、式では
++x + ++y * ++z
式++x
、++y
、およびは任意の順序++z
で評価できます。すべての優先順位は、 の結果が の結果に追加されることを示しています。 (y+1) * (z+1)
x+1
上位2つの回答はそれをかなりよく説明しています...私はそれを指摘したいと思います || は「OrElse」です。
左辺が true の場合、右辺は触れません。&& (AndAlso) の左側は、右側が false の場合は影響を受けません。
両側をインクリメントしたい場合は、| を使用します。と &。
http://msdn.microsoft.com/en-us/library/2h9cz2eb(v=VS.80).aspx
コンパイルされたコードが別の式の結果に応じて 1 つの式の評価をバイパスできる場合、論理演算はショートサーキットであると言われます。評価された最初の式の結果が操作の最終結果を決定する場合、最終結果を変更できないため、2 番目の式を評価する必要はありません。バイパスされた式が複雑な場合、またはプロシージャ コールが含まれる場合は、短絡によりパフォーマンスが向上する可能性があります。
MSDN には、部品がどのように "(評価されていない)" かを示す表があります。
パート 1 で結果が決定論的に事前に決定されているのに、パート 2 に触れる必要はありません。
私が C で作業してから長い時間が経ちましたが、私の記憶が正しければ、++ は単項演算子であり、常に二項演算子より優先されます。考えてみれば当然です。
異なるコンパイラ (および同じコンパイラの異なるバージョン) は異なる優先度を実装する可能性があるため、操作が順序に依存する場合は、知覚された演算子の優先度に依存しないでください。
いずれにせよ、b 定義 ++x は、x を使用する前にインクリメントする必要があることを意味するため、実行時に高い優先度が与えられると予想されます。
ダメダメダメ
if (++x || ++y && ++z) { /* ... */ }
はい
++x;
++y;
++z;
if (x || (y && z)) { /* ... */ }
仲間の苦情の後に編集:)
はい!
if (is_data_valid(x, y, z)) process_data(&x, &y, &z);