89

C++ で "bool" 値にビット演算子 &、|、および ^ を使用しない理由はありますか?

2 つの条件のうちの 1 つだけを真 (XOR) にしたい状況に遭遇することがあるので、^ 演算子を条件式に挿入します。また、条件のすべての部分を結果が true であるかどうか (ショートサーキットではなく) 評価したい場合もあるので、& と | を使用します。また、ブール値を累積する必要がある場合もあり、&= と |= は非常に便利です。

これを行ったとき、私は眉をひそめたことがありますが、コードは依然として意味があり、そうでない場合よりもクリーンです。これらをブールに使用しない理由はありますか? これに対して悪い結果をもたらす最新のコンパイラはありますか?

4

9 に答える 9

64

||および&&はブール演算子であり、組み込みの演算子は または のいずれtrueかを返すことが保証されていますfalse。他には何もありません。

|&および^ビットごとの演算子です。操作する数値のドメインが 1 と 0 だけの場合、それらはまったく同じですが、ブール値が厳密に 1 と 0 ではない場合 (C 言語の場合のように)、何らかの動作が発生する可能性があります。あなたは欲しくありませんでした。例えば:

BOOL two = 2;
BOOL one = 1;
BOOL and = two & one;   //and = 0
BOOL cand = two && one; //cand = 1

ただし、C++ では、型は aまたは a (暗黙的にそれぞれおよびに変換される)boolのいずれかのみであることが保証されているため、このスタンスから心配することはあまりありませんが、人々はコードでそのようなものを見ることに慣れていないという事実それをしないことについての良い議論をします。言うだけで、それで終わりです。truefalse10b = b && x

于 2008-08-23T20:06:20.430 に答える
33

Two main reasons. In short, consider carefully; there could be a good reason for it, but if there is be VERY explicit in your comments because it can be brittle and, as you say yourself, people aren't generally used to seeing code like this.

Bitwise xor != Logical xor (except for 0 and 1)

Firstly, if you are operating on values other than false and true (or 0 and 1, as integers), the ^ operator can introduce behavior not equivalent to a logical xor. For example:

int one = 1;
int two = 2;

// bitwise xor
if (one ^ two)
{
  // executes because expression = 3 and any non-zero integer evaluates to true
}

// logical xor; more correctly would be coded as
//   if (bool(one) != bool(two))
// but spelled out to be explicit in the context of the problem
if ((one && !two) || (!one && two))
{
  // does not execute b/c expression = ((true && false) || (false && true))
  // which evaluates to false
}

Credit to user @Patrick for expressing this first.

Order of operations

Second, |, &, and ^, as bitwise operators, do not short-circuit. In addition, multiple bitwise operators chained together in a single statement -- even with explicit parentheses -- can be reordered by optimizing compilers, because all 3 operations are normally commutative. This is important if the order of the operations matters.

In other words

bool result = true;
result = result && a() && b();
// will not call a() if result false, will not call b() if result or a() false

will not always give the same result (or end state) as

bool result = true;
result &= (a() & b());
// a() and b() both will be called, but not necessarily in that order in an
// optimizing compiler

This is especially important because you may not control methods a() and b(), or somebody else may come along and change them later not understanding the dependency, and cause a nasty (and often release-build only) bug.

于 2008-08-29T05:15:20.117 に答える
13

おもう

a != b

あなたが欲しいものです

于 2008-08-29T01:56:49.203 に答える
11

上げられた眉毛は、それをやめるのに十分なことを教えてくれるはずです. コンパイラーのためにコードを書くのではなく、まず仲間のプログラマーのためにコードを書き、次にコンパイラーのためにコードを書きます。コンパイラが機能したとしても、他の人を驚かせることはあなたが望むものではありません.ビットごとの演算子は、ブール値ではなくビット操作用です.
りんごもフォークで食べますか?それは機能しますが、人々を驚かせるので、やらないほうがいいです.

于 2008-08-23T20:00:16.653 に答える
10

ビットレベル演算子の欠点。

あなたが尋ねる:

「 C++ で "bool" 値にビット演算子&|、およびを使用しない理由はありますか? ^

はい、組み込みの高レベルのブール演算子である論理演算子!および&&||は、次の利点があります。

  • 引数のへの変換bool、つまり0および1序数値への変換が保証されています。

  • 最終結果が判明するとすぐに式の評価が停止する保証された短絡評価。これは、 TrueFalse、およびIndeterminate
    を持つツリー値ロジックとして解釈できます。

  • 読みやすいテキストの同等物notandおよびor、たとえ私がそれらを自分で使用していなくても。
    読者の Antimony がコメントで指摘しているように、ビットレベル演算子には代替トークン、つまりbitandbitorxorおよびcomplがありますが、私の意見では、これらはandorおよびよりも読みにくいと思いnotます。

簡単に言えば、このような高レベル演算子の利点は、ビットレベル演算子の欠点です。

特に、ビット単位の演算子には 0/1 への引数変換がないため、たとえば1 & 20、 while 1 && 2→が得られますtrue。また^、ビットごとの排他的 or は、このように誤動作する可能性があります。ブール値 1 と 2 は同じ、つまりtrueと見なされますが、ビットパターンと見なされて、それらは異なります。


C++ で論理的なeither/orを表現する方法。

次に、質問の背景を少し説明します。

「ときどき、2 つの条件のうち 1 つだけを真 (XOR) にしたい状況に遭遇することがあるので、条件式に ^ 演算子を挿入するだけです。」

まあ、ビット演算子は論理演算子よりも優先順位が高いです。これは特に、次のような混合式で

a && b ^ c

おそらく予期しない結果が得られますa && (b ^ c)

代わりにただ書く

(a && b) != c

言いたいことをより簡潔に表現する。

複数の引数の場合、/またはジョブを実行する C++ 演算子がありません。たとえば、それは「どちらか、または真である」a ^ b ^ cという表現ではありません。代わりに、「奇数のとが真」と表示されます。これは、そのうちの 1 つまたは 3 つすべてである可能性があります…abcabc

a一般的な either/or whenとare of typeを表現するにはb、次のように記述します。cbool

(a + b + c) == 1

または、引数なしで、それらを次boolのように変換します。bool

(!!a + !!b + !!c) == 1


&=ブール値の結果を蓄積するために使用します。

さらに詳しく説明すると、

「ブール値を累積する必要がある場合もありますが、&=これ|=?は非常に便利です。」

これは、すべての条件が満たされているか、いずれかの条件が満たされているかどうかをそれぞれチェックすることに相当し、ド・モルガンの法則は、ある条件から別の条件に進む方法を教えてくれます。つまり、そのうちの 1 つだけが必要です。原則として- 演算子として使用できます(古き良き George Boole が発見したように、論理 AND は乗算として非常に簡単に表現できます) が、それはコードの管理者を困惑させ、おそらく誤解を招くと思います。*=&&=

以下も考慮してください。

struct Bool
{
    bool    value;

    void operator&=( bool const v ) { value = value && v; }
    operator bool() const { return value; }
};

#include <iostream>

int main()
{
    using namespace std;

    Bool a  = {true};
    a &= true || false;
    a &= 1234;
    cout << boolalpha << a << endl;

    bool b = {true};
    b &= true || false;
    b &= 1234;
    cout << boolalpha << b << endl;
}

Visual C++ 11.0 および g++ 4.7.1 での出力:

真実
間違い

結果の違いの理由は、ビットレベルがその右側の引数&=の変換を提供しないためです。bool

では、これらの結果のどれを使用したいと思います&=か?

前者の場合、true(上記のように) 演算子または名前付き関数をより適切に定義するか、右辺式の明示的な変換を使用するか、更新を完全に記述します。

于 2012-12-21T07:56:36.213 に答える
3

パトリックの答えに反して、C++には^^排他的論理和の短絡を実行するための演算子がありません。少し考えてみると、^^演算子を使用しても意味がありません。排他的論理和を使用すると、結果は常に両方のオペランドに依存します。ただし、非「ブール」型に関するPatrickの警告は、と比較しboolた場合にも同様に当てはまります。この典型的な例の1つは、ゼロ以外の、、、またはの3つの状態を返すWindows関数です。1 & 21 && 2GetMessage()BOOL0-1

&の代わりに&&、の|代わりに使用||することは珍しいタイプミスではないので、意図的にそれを行っているのであれば、その理由をコメントする価値があります。

于 2008-09-16T05:54:41.650 に答える
2

パトリックは良い点を指摘しました。私はそれらを繰り返すつもりはありません。ただし、適切な名前のブール変数を使用して、可能な限り「if」ステートメントを読みやすい英語に減らすことをお勧めします。たとえば、これはブール演算子を使用していますが、同様にビットごとに使用してブールに適切な名前を付けることができます。

bool onlyAIsTrue = (a && !b); // you could use bitwise XOR here
bool onlyBIsTrue = (b && !a); // and not need this second line
if (onlyAIsTrue || onlyBIsTrue)
{
 .. stuff ..
}

ブール値を使用する必要がないように思えるかもしれませんが、主に次の 2 つの点で役立ちます。

  • 「if」条件の中間ブール値により条件の意図がより明確になるため、コードが理解しやすくなります。
  • ブール値のビット単位演算子など、非標準または予期しないコードを使用している場合、人々はこれを行った理由をより簡単に理解できます。

編集:「if」ステートメントの条件が必要だと明示的に言っていませんでした(これは最も可能性が高いようですが)、それが私の仮定でした。しかし、中間ブール値の私の提案はまだ有効です。

于 2008-08-24T17:42:30.550 に答える
0

IIRC、多くの C++ コンパイラは、ビット演算の結果を bool としてキャストしようとすると警告します。コンパイラを満足させるには、型キャストを使用する必要があります。

if 式でビットごとの操作を使用することは、おそらくコンパイラによるものではありませんが、同じ批判に役立ちます。ゼロ以外の値はすべて true と見なされるため、「if (7 & 3)」などは true になります。この動作は Perl では許容されるかもしれませんが、C/C++ は非常に明示的な言語です。スポックの眉はデューデリジェンスだと思います。:) 「== 0」または「!= 0」を追加して、目的が何であるかを完全に明確にします。

とにかく、それは個人的な好みのように聞こえます。lint または同様のツールを使用してコードを実行し、それが賢明でない戦略であると考えているかどうかを確認します。個人的には、コーディングミスのように見えます。

于 2008-08-29T02:08:12.937 に答える