42

フォームのステートメントをコーディングする必要がありました

a = a || expr;

whereを評価し、結果をiffexprに代入するが設定されていません。これは、論理 OR の短絡機能に依存しています。aa

上記を短く書くと、もちろん、

a ||= expr;

しかし (驚いたことに) C には論理代入演算子がありません。

だから私の質問は2つあります。まず、標準 C で最初のステートメントを書くためのより短い方法はありますか (三項演算子はさらに悪いです - 3 回a = a ? a : exprスペルアウトする必要がありますa)。

次に、C に論理代入がないのはなぜですか? 私が考えることができる考えられる理由は次のとおりです。

  • 文法の解析が難しくなりますか?
  • これらの場合の短絡の処理には微妙な点がありますか?
  • それは不必要だと考えられていました (しかし、それはすべての演算子割り当てに対する議論ではありませんか?)

編集

この質問のロックを解除してください:

  • それがリンクされている質問(の複製とされるものとして)は、まだ回答されていません。その質問に対する(受け入れられた)回答||=は、の機能を複製するため存在しないと述べてい|=ます。それは間違った答えです。|=短絡しません。

  • C と C++ は同じ言語ではありません。なぜCにそれがないのか知りたいです。実際、C++ のような派生言語、特に Java (Edmund の回答で示唆されているようなレガシー コードの問題に悩まされていない) は、この問題をさらに興味深いものにしています。

編集2

本来の意図が間違っていたようです。ステートメントa = a || expr( whereaは整数でありexpr、整数値を返します。最初にaとの両方exprが暗黙的に「ブール値」に変換され、次に「ブール値」が に割り当てられaます。これは正しくありません — 整数値は失われます。ありがとうございます。 、イェンス、エドマンド。

したがって、質問の最初の部分では、代替手段ではなく:)、私の意図をコーディングするための正しい方法は次のようになります。

if (!a) a = expr;

また

a = a ? a : expr;

それらは同じように最適化する必要があります(私は思います)が、個人的には最初のものを好みます(a入力するものが1つ少ないため)。

ただし、質問の2番目の部分はまだ残っています。Jens と Edmund が のあいまいさについて示した議論は、a ||= exprにも同様に当てはまりますa = a || expr。代入ケースは、単純に通常のケースとして扱うことができます。

  • aブール値に変換
  • true の場合、式全体の値はのブール値と等しくなります。a
  • それ以外の場合は を評価しexpr、結果をブール値に変換し、 に代入しaて返します

上記の手順は、割り当てと通常のケースの両方で同じようです。

4

5 に答える 5

9

a ||= expr相当品の短絡評価で問題ありa = a || expr

OPのアサーションを考慮a ||= exprするような機能を持たせるには:a = a || expr

「ステートメントではa = a || expr...、最初に a と expr の両方が暗黙的に「ブール値」に変換されます。」

これは完全に正しくありません。 に評価さexprれる場合は変換されません。これにより、プログラムの状態に影響を与えるような、または何らかの関数になるはずです。atrueexprscanf()rand()

のようなコードa ||= scanf("%d", &i) != 1;は、値が false のデータのみをスキャンしようとしますa||このように言語を拡張することは可能ですが、現在のとのセットに短絡演算子を追加すると&&、明確な単純化よりも多くのコーディングの問題が発生する可能性があります。

一方、難読化されている場合は、関数がエラー時にゼロ以外のコードを返すコードをすばやく作成する方法。

// Perform functions until an error occurs.
bool error = foo1();
error &&= foo2();  // Only valid if C was extended with &&=
error &&= foo3();
于 2015-07-14T21:31:05.217 に答える
5

演算子||との戻り値の型&&は、左の引数の型と同じではないためです。

||andの戻り値の型&&は常にint1ですが、左の引数は任意の整数型、浮動小数点型、またはポインター型にすることができます。オペランドも同じ型である必要はありません。したがってx ||= y、asx = x || yおよびx &&= yasx = x && yを他の拡張割り当てと一致するように定義すると、ほとんどの型の引数に結果を格納できなくなります。

x ||= yasif(!x) x = yx &&= yasなど、他の定義を考え出すこともできますがif(!y) x = y、それは明確ではなくそれほど有用ではないため、含まれていません。

1 C++ ではbool.

于 2014-04-16T12:28:44.547 に答える
3

演算子が存在しない特定の理由が見つかりません(C99)。

したがって、私が見つけることができる唯一の理由は、C89 にはブール型がなく、それらのブール演算子はif's でのみ使用されることを意図していたということです。

例:

int i = 5;

/* This should not make any difference,
   since or'ing with false, shouldn't change
   the value... dib di dib diddy...*/
i ||= 0; /* Actually: i = i || 0, which gives 'true' */

iは「1」になりましたが、これはほとんどの人にとって非常に直感的ではありません。

この演算子は明らかに、ブール型がなければ明確化やコーディングの改善をもたらしません。これは、別の演算子と論理和をとることを意味します。

私の意見では、a ||= b;asの実装はif(!a) a = b;非常に簡単で、すでに Lua などによって実装されています。

ですから、C が設計された方法で設計された理由は少し疑問に思われます。この質問が C++ に関するものである場合、たとえば Bjarne Stroustrup に聞いて、彼に何が起こったのかを尋ねることができます。これは事実ではないので、これは行き止まりのように思えます。なぜなら、標準はかなり前に書かれていて、もう人々になぜh ***.

一方、この不完全な演算子セットは、(私の意見では) あなたのものと同様の表記法を使用してすでに完全に作成されているはずです。

少しでもお役に立てれば幸いです。

于 2015-02-26T10:53:44.610 に答える
3

簡単な答えはブール演算子だと思います||.Cでは、「ブール値」は0または1です。オペランドは暗黙的にブール値に変換されます(仕様が実際に言っていることを確認していませんが、Cの動作です)、結果はブール値です。

||このパターンをサポートするようにセマンティクスを変更することは、実行可能である可能性があります-誰かが常に行われていることに依存するまでは .

于 2010-08-17T09:38:48.197 に答える