web-dev-qa-db-ja.com

if(mask&VALUE)またはif((mask&VALUE)== VALUE)?

おそらく、次のようなenumビットマスク方式に精通しています。

enum Flags {
    FLAG1 = 0x1,
    FLAG2 = 0x2,
    FLAG3 = 0x4,
    FLAG4 = 0x8,

    NO_FLAGS = 0,
    ALL_FLAGS = FLAG1 | FLAG2 | FLAG3 | FLAG4
};

f(FLAG2 | FLAG4);

次のようなマスクの特定のビットをテストする多くのコードを見てきました

if ((mask & FLAG3) == FLAG3)

しかし、それはこれと同等ではありませんか?

if (mask & FLAG3)

最初のバージョンを使用する理由はありますか?私の意見では、2番目の短いバージョンの方が読みやすいです。

たぶん、真の値を1に変換するべきだと考えるCプログラマーの残りの習慣でしょうか。 (それでも、長いバージョンは、代入またはreturnステートメントの方が条件ステートメントのテストよりも意味があります。)

36
aschepler

コンストラクトif ((mask & FLAG3) == FLAG3)は、FLAG3のallビットがマスクに存在するかどうかをテストします。 if (mask & FLAG3)anyが存在するかどうかをテストします。

FLAG3に正確に1ビットが設定されていることがわかっている場合、それらは同等ですが、複合条件を定義している可能性がある場合、それが意味するものであれば、すべてのビットを明示的にテストする習慣に入るほうがより明確です。

80
David Gelhar

それがビットセット用である場合、singleビットのみを比較する必要がある場合、if(mask & value)を使用しても問題ありません。

ただし、IPアドレスがint32に格納されていて、それが192.168.*かどうかを知りたい場合は、次のようにする必要があります。

if((ip & 0xFFFF0000) == 0xC0A80000) // assuming some endianness representation.
2
Benoit

これらのステートメントが実際に同等である単一ビット値の場合でも、私は常に明示的な比較を優先します。

  1. それは意図をより明確にします。私たちは本当にフラグを比較することに興味がありますある。 _(x & Flag) == Flag_は確立されたパターンであり、瞬く間に処理して認識できます。

  2. 私は通常、暗黙的な変換よりも明示的な変換を優先します。失敗状態の例外を作成します(たとえば、if (file)ではなくif (file.good())と書き込みます)が、数値を扱う場合、0は「失敗状態」ではなく、他の数値と同じです。ブール値のコンテキストで別の扱いをするのは好きではありません。

2
Konrad Rudolph

ifはブール値を取ります(bool)。前者の式は直接bool型ですが、後者は暗黙的にboolに変換される数値です。

1
Daniel Daranas

結果がゼロ以外の場合、条件は真になります。あなたの例では、両方の操作の結果は同等であり、2番目のオプションは、他の任意の数値よりも簡単にゼロをテストできるCPUがあるため、わずかに速くなる可能性もありますが、

明らかに、チェックしている値が複数のビットで構成されている場合、2番目のオプションは実行できません。その場合、最初のオプションを使用する必要があります。これは、同時にいくつかのビットをチェックしている場合にも当てはまります。

1
EboMike

最初の構文if (mask & FLAG3)は、「少なくとも1つの共通ビットがフラグとマスクにある場合」を意味します。たとえば、フォーマットとsupported_formatsの間でanyビットが共通である場合、if (formats & supported_formats)はtrueになります。

2番目の構文if (mask & FLAG3) == FLAG3は、「FLAG3のすべての設定ビットがマスクで設定されている場合」を意味します。たとえば、if (things_you_have & things_required) == things_requiredは、all things_requiredがthings_you_haveにある場合にtrueになります。

ここにいくつかの特別なケースの簡単なヒットがあります:

  • ために FLAG_WITH_EXACTLY_ONE_BIT_SET、どちらの場合も機能します。
  • ために OBSOLETE_FLAG_SET_TO_ZERO、最初のケースは常にfalseを返します。
  • ために FLAG_WITH_MULTIPLE_BITS_REQUIRED、またはFLAG_WHICH_IS_REALLY_TWO_FLAGS_COMBINED_WITH_AN_OR、最初のケースは、そうすべきでないときにtrueを返します。 2番目のケースは正しく戻ります。

FLAG_WITH_EXACTLY_ONE_BIT_SETの場合は、フラグの値が変更されたときの奇妙な問題を回避するために、2番目の構成でコーディングする必要があります。プロファイラーからすべての操作を絞るように指示されない限り、明示的にしてください。

0
Charles Merriam