2009-09-10 3 views
20

私は、1つまたは複数の真偽状態にある可能性のあるオブジェクトを持っている場合、プログラマがいくつかのブール値を使用するのではなく、フラグ+ビットマスクを頻繁に使用する理由を少し不明瞭にしてきました。一連のブール値ではなく、なぜフラグ+ビットマスクを使用するのですか?

これは.NETフレームワーク上にあります。必ずこれが最良の例ですが、.NETフレームワークには、次のを持っている場合ではない:

public enum AnchorStyles 
{ 
    None = 0, 
    Top = 1, 
    Bottom = 2, 
    Left = 4, 
    Right = 8 
} 

だから、アンカースタイルを考えると、我々は選択された状態のどの把握するビットマスクを使用することができます。しかし、可能な値ごとにboolプロパティが定義されたAnchorStyleクラス/構造体、または個々の列挙型値の配列で同じことを達成できるようです。

もちろん私の質問の主な理由は、自分のコードで同様の習慣を守らなければならないかと思います。

なぜこのアプローチを使用しますか?

  • メモリ消費量は少ないですか? (は、boolの配列/構造体より少なく消費するようなと思われます)
  • 構造体または配列よりも優れたスタック/ヒープパフォーマンスですか?
  • 比較操作が高速ですか?より速い値の追加/削除?
  • これを書いた開発者にとって、より便利ですか?
+2

強引な議論ではありませんが、メモリ消費は少なくなります。これはint(4バイト)を使い、各ブールは1バイトを使います。したがって、4つのboolは1つのintと同じものを使います。 32個のboolは32バイトを使いますが、すべてのboolは同じ列挙型になります。推奨されていないパスに行くと、enumは8バイト長(sizeof(long))にすることができます。 –

+0

これを明確にしていただきありがとうございます。それは私にこのポストにつながった:http://stackoverflow.com/questions/294905/why-in-net-system-boolean-takes-4-byte –

+0

回答から、enumフラグは構造体よりも軽量であることは明らかです/ boolの配列はメモリの観点から見ています。しかし、BitVector32やBitArrayなど、.NET Frameworkのクラスがタスクに適しているようです。ストレージにBitVector32(uintでバックアップ)を使用し、特定のインデックスでビット(bool)を取得/設定するプロパティを提供する構造体はどうでしょうか? Windowsフォームはこれを行うようです。開発者向けのコードが増えましたが、パフォーマンスが優れているようで、カプセル化によって下流のAPIコンシューマーが使いやすくなりました。うん? –

答えて

13

これは伝統的にメモリ使用量を削減する方法でした。だから、プログラミング技術として

:-)、はいC#でそのかなり時代遅れ、

それは今日のシステムで廃止とすることができ、あなたはboolsの配列を使用することは非常に大丈夫だろう、しかし...

ビットマスクとして保存された値を比較するのは速いです。ANDおよびOR論理演算子を使用し、結果の2つの整数を比較します。

かなり少ないメモリしか使用しません。あなたのサンプル値の4つすべてをビットマスクに入れると、半分のバイトが使用されます。 boolの配列を使用すると、配列オブジェクトに数バイトを加え、各boolに長い単語を使用します。百万の値を保存する必要がある場合は、ビットマスクのバージョンが優れている理由が正確にわかります。

管理が簡単ですが、単一の整数値を扱うだけで済みますが、boolの配列はデータベースとはかなり異なった方法で格納されます。

メモリレイアウトのため、配列よりもはるかに高速です。 1つの32ビット整数を使用するのとほぼ同じくらい速いです。私たちは皆、あなたがデータ操作のために得ることができるほど速いことを知っています。

1

スピードと効率のためです。本質的にあなたが扱っているのは、単一のintです。

if ((flags & AnchorStyles.Top) == AnchorStyles.Top) 
{ 
    //Do stuff 
} 
+0

それはかなり高いレベルの答えです。より速く/より効率的な操作とその理由について具体的に説明できますか?またはあなたの主張を正当化する記事へのリンク? –

+0

ネイティブタイプや単純なロジック式を使った作業が高速かつ効率的であるという証拠を本当に必要としますか? – ChaosPandion

+0

操作の順序を忘れないでください。そこでは、ビット単位の演算を括弧で囲む必要があります。 –

12
  • 簡単に任意の順序で複数のフラグを設定します。

  • データベースに0101011というセリフを保存して簡単に取得できます。

+2

別個の列であっても、SQL Serverはこれらを1バイトに最適化します。http://msdn.microsoft.com/en-us/library/ms177603.aspx – AaronLS

6

とりわけ、新しいビットの意味をビットフィールドに追加する方が、新しいブール値をクラスに追加する方が簡単です。また、一連のブール値よりもビットフィールドをあるインスタンスから別のインスタンスにコピーする方が簡単です。

+0

ブール値をクラスに追加することは、次のように簡単です。 bool newState; コピーに関しては、構造体をコピーするのと同じように思えます。 –

+0

@Winston:シリアル化形式が変更され、古いデータの既定値を受け入れ、古いバージョンが未知のフィールドを捨てないような良いシリアライザは見つけるのが難しいです。バイナリインターフェイスが変更されると、必要な更新の連鎖が発生し、構造に対する完全な検証サポートが必要になります。 (もちろん、*未知のビットは無視されるか、または「未知のビットが原因でエラーになる」という明示的な表現が必要です。また、実装レベルでは、全体としての処理が簡単です。 – peterchen

+1

@WinstonどうすればAPIを作成できますか?それで、あなたの新しいバージョンにアップグレードする皆さんは、新しいboolがメソッドに追加されたため、コードを変更する必要があります。列挙型の場合は、それを使用して同じコードを保持するために、そこに変更を加える必要はありません。それはなぜですか?NETフレームワークはブール値よりもenumを優先します。 –

3

実際には、enumがバイトから派生している場合は、主にパフォーマンスが向上します。 極端な場合、各列挙型の値は、256までのすべての組み合わせを含むバイトで表されます。ブール値との可能な組み合わせの可能性は256バイトになります。

しかし、それでも、私はそれが本当の理由だとは思わない。私がそれらを好む理由は、C#がそれらの列挙型を扱うために私に与える力です。 1つの式で複数の値を追加できます。私もそれらを削除することができます。列挙型を使用して、一度に複数の値を1つの式と比較することもできます。ブール値では、コードはもっと冗長になります。

+3

256の組み合わせがありますが、8つのフラグしかありません。それらを混同しないでください。 – Dykam

+0

申し訳ありませんが、私の英語は十分明確ではありませんでした。あなたが正しい。 –

+1

boolを使用して256の組み合わせがありますか?それは8ブール値です。 8個のbool値は256バイトではありません。 – CoperNick

5

また、メソッドをより明確にすることもできます。 10のbool対1のビットマスクを持つ方法を想像してください。

2

かなり深刻なメモリ制限(あまりありそうもない)を扱っていない限り、私は列挙型フラグを使用しないことをお勧めします。メンテナンスのために最適化されたコードを書くべきです。

いくつかのブール値のプロパティを使用すると、コードの読み取りと理解、値の変更、およびIntellisenseのコメントの提供が容易になり、バグの可能性を減らすことができます。必要に応じて、常にenumフラグフィールドを内部的に使用することができます。値の設定/取得がブール値のプロパティで公開されていることを確認してください。

3

レイモンド・チェンはa blog post on this subjectです。

確かに、ビットフィールドを使用すると、コードサイズ、debuggability、および 減少し、マルチスレッドで コストに対してそれのバランスを取る必要があり データメモリを節約する、しかし。

他にも言われているように、その時間は主に過去です。それはやってみると魅力的ですが、ちょっとした手間が楽しくてクールだと思っていますが、もはや効率的ではなく、メンテナンス面での重大な欠点があります。データベースでうまく動作せず、あなたは十分なメモリを持っています。

+2

レイモンドはビットマスクではなくビットフィールドについて話しています。 – gbjbaanb

1

ドメインモデルの観点からは、状況によっては現実をモデル化するだけです。 AccountIsInDefaultやIsPreferredCustomer、RequiresSalesTaxStateのような3つのブール値がある場合、それらを単一のFlags装飾列挙に追加するのは意味がありません。同じドメインモデル要素の3つの異なる値ではないからです。

しかし、あなたのようなブール値のセットを持っている場合:

[Flags] enum AccountStatus {AccountIsInDefault=1, 
     AccountOverdue=2 and AccountFrozen=4} 

または

[Flags] enum CargoState {ExceedsWeightLimit=1, 
     ContainsDangerousCargo=2, IsFlammableCargo=4, 
     ContainsRadioactive=8} 

そして、アカウントの合計状態、(または貨物)を格納することができることは有用ですONE変数には、値が可能な状態の組み合わせを表すことができる1つのドメイン要素を表す。

1
  1. スペース効率 - 1ビット
  2. 時間効率 - ビットの比較は、ハードウェアによって素早く処理されます。
  3. 言語の独立性 - 異なる言語/プラットフォーム間でブール値の実装について心配する必要のない、多数の異なるプログラムによってデータが処理される場合があります。

ほとんどの場合、これらはメンテナンスの面でトレードオフの価値はありません。しかし、それが有用である場合があります:私はいくつかのレガシーソフトウェアにトレースするため、いくつかの情報を追加する必要がありましたたら -

  1. ネットワークプロトコルは - メッセージ
  2. レガシーソフトウェアの縮小に大きな節約があるでしょう。

ヘッダーを変更するためのコスト:何百万ドルもの努力。 ヘッダーの2バイトの情報を使用していなかったため、この情報は使用されませんでした:0

もちろん、この情報にアクセスして操作するコードには追加コストがかかりましたが、アクセサーを定義した後はブーリアンを使用するよりもメンテナンス性が向上しました。

+1

1.スペース効率は、非常に高密度のパッキング環境または極限環境にのみ適用されます。 2.時間効率は、マスクの効率的な使用に依存します(単一のブール値を比較するよりも、単一ビットをマスクして比較するのが確実ではありません)。 3.該当しません。ブール型を使用すると、ブール型が誤って使用されます。 – user2864740

関連する問題