C#でその演算子の短絡ORバリエーションと非短絡バリエーションの両方があるのはなぜですか?


9

定期的に、私はこれについて疑問に思います:

短絡ORは常に、短絡されていないOR演算子と同じ値を返しますか?

ショートサーキットORは常により迅速に評価されると思います。では、一貫性を保つために、短絡されていないOR演算子がC#言語に含まれていたのでしょうか。

私は何を逃したのですか?


9
同じ戻り値-はい。同じ副作用-いいえ。
Job

2
仮定しf()、昇給に例外を考慮true || f()してtrue | f()。違いがわかりますか?前者の式はに評価されtrue、後者の評価では例外がスローされます。
スカーフリッジ

回答:


25

両方のオペランドは、ブール型を持たないCから来た、異なるもののためのものでした。短絡バージョン|| ブール値でのみ機能しますが、非短絡バージョン| 整数型で機能し、ビット単位のORを実行します。たまたま、0または1の単一ビットで表されるブール値の非短絡論理演算として機能しました。

http://en.wikibooks.org/wiki/C_Sharp_Programming/Operators#Logical


10
リンクの+1。この質問を読んだとき、私は「何ですか」のようでした。なぜなら、これらの正式名称は論理的でビット単位の論理和であり、それらがどのように機能するかの副作用である短絡や非短絡ではないからです。
stijn

1
+1「ブール値のオペランドのみで動作する」と表示されます
CarneyCode

2
チェックする必要がありましたが、実際には、|演算子が2つのブール値orに適用されると、2つの整数値に適用される場合と同じようにCILで同じ演算子にコンパイルされます- 条件付きで||使用brtrueしてCILにコンパイルされるのとは異なりますジャンプ。
クエンティンスターリン

13

|(ビットごとの論理和)は、のような型の非短絡回路でなければなりませんint。これは、ほとんどの場合|、正しい結果を計算するために式の両側を計算する必要があるためです。たとえば、どのような結果になり7 | f(x)ますか?

f(x)評価されない場合はわかりません。

さらに、この演算子boolがに対して非短絡である場合、この演算子をに対して短絡させることは矛盾しintます。ちなみに、|意図的に論理比較を行ったことは一度もない|ので、論理演算子と言えば非常に不便です。

|| ただし、論理的な比較の場合は、短絡評価が適切に機能します。

同じことは、それらの演算子の起源が存在するCおよびC ++についても有効です。


5

これは正しいです。短絡OR演算子(||)は常に非短絡OR演算子(|)と同じ値を返します。(*)

ただし、最初のオペランドがtrueの場合、短絡演算子は2番目のオペランドを評価しませんが、非短絡演算子は常に両方のオペランドを評価します。これはパフォーマンスに影響を与える可能性があり、場合によっては副作用にも影響します。

したがって、両方の使用法があります。パフォーマンスを重視し、第2オペランドの評価で副作用が発生しない場合(または、それらを重視しない場合)は、必ず短絡演算子を使用してください。 。何らかの理由であなたがいる場合でも、必要な第二オペランドの副作用を、あなたは非短絡演算子を使用する必要があります。

非短絡演算子を使用する必要がある例:

if( write_customer_to_database() != SUCCESS |
    write_supplier_to_database() != SUCCESS |
    write_order_to_database() != SUCCESS )
{
    transaction_rollback();
}

(*)最初のオペランドをfalseに評価すると、副作用によって2番目のオペランドがfalseではなくtrueに評価される、実際に異常なシナリオを除きます。


2
+1しかし、成功または失敗を示すために関数を使用すること(例のように)とは別に、それを追加したいと思います。副作用のある関数は一般に回避する必要があります...
Marjan Venema

1
はい、おそらくそれが今日まで私が非短絡演算子を使用したことがない理由であり、可能性は私がこれまでにないほどスリムです。
Mike Nakis、2011

その例は、厳密な左から右の順序で評価されるオペランドに依存します。C#はこれを保証しますが、多くの同様の言語(CおよびC ++を含む)は保証しません。
キース・トンプソン

トランザクションのいずれかが失敗するとすべてのトランザクションがロールバックされるため、その特定の例では短絡評価は意味をなさないでしょうか?(私は呼び出しのセマンティクスについていくつかの仮定をしています。)
キース・トンプソン

@KeithThompsonそうです、非短絡評価は不要な処理を引き起こします。この意味で、この例は少し不十分ですが、以下の場合の短絡評価の真実は変わらないので、変更を保証するのはそれほど不十分ではありません。 write_customer_to_database()が成功すると、残りのwrite _...関数が呼び出されることはありません。失敗した場合に不要な操作を実行するよりも、成功した場合は正しく機能する方が適切です。
Mike Nakis、2011

4

非短絡バリアントを使用する理由は2つあります。

  1. 副作用を維持する(ただし、一時変数を使用したコーディングの方が明確です)

  2. 短絡のフォークを回避することでタイミング攻撃を阻止します(これにより、2番目のオペランドが変数である場合でもランタイム効率が向上する可能性がありますが、コンパイラーがとにかく行うマイクロ最適化です)


これが唯一の正しい理由であり、なぜこれが最高票で受け入れられた回答ではないのか
分かり

2

演算子の右側の句に副作用があり、プログラマが戻り値をチェックする前に両方の副作用を発生させたい場合。


5
ねえ。そのようにコーディングしないでください。副作用に依存する場合、2つの異なる式を使用し、結果を割り当てて、後でテストします。
Konrad Rudolph
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.