C#バイナリリテラル


186

16進数の前に0xを付けるなど、C#でバイナリリテラルを書き込む方法はありますか?0bは機能しません。

そうでない場合、それを行う簡単な方法は何ですか?ある種の文字列変換?


2
定数を使用して適切な名前を付ければ、10進数で記述する必要があるという事実は問題になりません。個人的に私は読んでもらいたいと思いますif (a == MaskForModemIOEnabled)ではなくif (a == 0b100101)
ラッセV. Karlsenの

1
別のメモ:ビットフィールドが必要なためにこの投稿を見つけた場合は、flags-attributeを検討してください
toxvaerd

16
上記のビットフィールドを定義する場合を除いて、どちらも非常に優れたアドバイスです。これらの名前付き定数の定義は、バイナリリテラルで読み書きしやすくなっています。[フラグ]列挙型数量{なし= 0、1 = 1、いくつか= 0b10、最も= 0b100、すべて= 0b111}
brianary

1
価値のあることとして、バイナリリテラルのサポートはRoslynで計画されています。
ジョーホワイト

C#6.0ではまだサポートされていませんよね?vs2015ではバイナリリテラルを使用できません:/
anhoppe

回答:


145

C#7.0は、バイナリリテラル(およびアンダースコア文字によるオプションの桁区切り記号)をサポートしています。

例:

int myValue = 0b0010_0110_0000_0011;

Roslyn GitHubページにも詳細情報があります


3
@ D.Singh C#7リストに表示されています。github.com/dotnet/roslyn/issues/2136
Danation 2015

9
甘い!VS2017 / C#7で素晴らしい働きをします。
STLDev

1
C#のバイナリリテラルはビッグエンディアンですが、x86では整数はリトルエンディアンであるInt16 = 0b0010_0110_0000_0011ことを覚えておくと役立ちます{ 0b0000_0011, 0b0010_0110 }

1
@Daiは16進リテラルと同じです。つまり、すべての定数はビッグエンディアンですが、インテル/ AMDおよびほとんどのARMではリトルエンディアンが格納されています。0xDEADBEEFとして保存されます0xEF 0xBE 0xAD 0xDE
コールジョンソン

168

更新

C#7.0にバイナリリテラルが追加されました。

[Flags]
enum Days
{
    None = 0,
    Sunday    = 0b0000001,
    Monday    = 0b0000010,   // 2
    Tuesday   = 0b0000100,   // 4
    Wednesday = 0b0001000,   // 8
    Thursday  = 0b0010000,   // 16
    Friday    = 0b0100000,   // etc.
    Saturday  = 0b1000000,
    Weekend = Saturday | Sunday,
    Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday
}

元の投稿

トピックは列挙型でビットベースのフラグ値を宣言するようになっているようですので、この種のことには便利なトリックを指摘する価値があると思いました。左シフト演算子(<<)を使用すると、ビットを特定のバイナリ位置にプッシュできます。これを、同じクラス内の他の値で列挙値を宣言する機能と組み合わせると、ビットフラグ列挙の非常に読みやすい宣言構文が得られます。

[Flags]
enum Days
{
    None        = 0,
    Sunday      = 1,
    Monday      = 1 << 1,   // 2
    Tuesday     = 1 << 2,   // 4
    Wednesday   = 1 << 3,   // 8
    Thursday    = 1 << 4,   // 16
    Friday      = 1 << 5,   // etc.
    Saturday    = 1 << 6,
    Weekend     = Saturday | Sunday,
    Weekdays    = Monday | Tuesday | Wednesday | Thursday | Friday
}

26
@ColeJohnson:多くの開発者はそれを好みます。私は一部の開発者ほど頭の中で16進数を変換するのが得意ではありません。時には、最も低い共通項に対応するのが最善の場合もあります。
StriplingWarrior 2012年

2
列挙型は定数として構築されるため、これが最も効果的な方法だと思います。オプションの[Flags]属性を使用すると、ビット単位の演算で使用できます(質問には直接関係しませんが、バイナリリテラルを記述するときに特に役立ちます)。もう1つの興味深い可能性は、列挙型を組み込み型として強制することです(この例では、「Days」の後に「:byte」を追加します)。bit.ly/MKv42Eの組み込み
カリガリ

Enumで0フラグを宣言することはかなり悪い習慣ですが、それは実際には非常に読みやすいです
MikeT

5
@MikeT:その最後の考えについて詳しく説明(または詳しく説明するリンクを提供)できますか?値が単純に初期化されなかったときに検出してフェイルファストできるようにしたいので、「1」で始まる列挙型を宣言することがよくあります。しかし、デフォルト値が実際に意味をなすいくつかの状況があり、その値の名前を追加しても何も問題はないと思います。
StriplingWarrior 2015年

3
@MikeT From ca1008"FlagsAttributeが適用されている列挙がゼロ値のメンバーを定義している場合、その名前は 'None'にして、列挙に値が設定されていないことを示す必要があります。したがって、「なし」と呼ばれる場合、デフォルト値として機能するように追加することは完全に有効です。全体的に、デフォルトで初期化されたフィールドの値に実際に表示する名前がある場合、私にはすっきりしているように見えます。
Nyerguds

115

整数と16進数のみが直接、恐れています(ECMA 334v4):

9.4.4.2整数リテラル整数リテラルは、int、uint、long、およびulong型の値を書き込むために使用されます。整数リテラルには、10進数と16進数の2つの形式があります。

解析するには、以下を使用できます。

int i = Convert.ToInt32("01101101", 2);

4
この回答の更新として、最新の最新情報(2014年7月)を使用します。C#6.0では、バイナリリテラルが導入されています。下部にある私の最新の回答wayyyyyyをご覧ください...
BTownTKD 2014年

1
@BTownTKDそれは受け入れられた答えなので、あなたの答えは実際にはトップです:)。
RBT

25

列挙型のビットフラグに関する@StriplingWarriorの回答に加えて、ビットシフトを上方にカウントするために16進数で使用できる簡単な規則があります。シーケンス1-2-4-8を使用して、1列を左に移動し、繰り返します。

[Flags]
enum Scenery
{
  Trees   = 0x001, // 000000000001
  Grass   = 0x002, // 000000000010
  Flowers = 0x004, // 000000000100
  Cactus  = 0x008, // 000000001000
  Birds   = 0x010, // 000000010000
  Bushes  = 0x020, // 000000100000
  Shrubs  = 0x040, // 000001000000
  Trails  = 0x080, // 000010000000
  Ferns   = 0x100, // 000100000000
  Rocks   = 0x200, // 001000000000
  Animals = 0x400, // 010000000000
  Moss    = 0x800, // 100000000000
}

右の列から下にスキャンして、パターン1-2-4-8(シフト)1-2-4-8(シフト)...


元の質問に答えるために、16進リテラルを使用するという@Sahuaginの提案に2番目です。これが問題になるのに十分な頻度で2進数を処理している場合、16進数のこつを取得することは価値があります。

ソースコードで2進数を確認する必要がある場合は、上記のようなバイナリリテラルを含むコメントを追加することをお勧めします。


23

あなたはいつでもあなたが求めている値を含む準リテラル、定数を作成することができます:

const int b001 = 1;
const int b010 = 2;
const int b011 = 3;
// etc ...
Debug.Assert((b001 | b010) == b011);

それらを頻繁に使用する場合は、静的クラスにラップして再利用できます。

ただし、ビットに関連するセマンティクス(コンパイル時に既知)がある場合は、少しトピックから外れていますが、代わりにEnumを使用することをお勧めします。

enum Flags
{ 
    First = 0,
    Second = 1,
    Third = 2,
    SecondAndThird = 3
}
// later ...
Debug.Assert((Flags.Second | Flags.Third) == Flags.SecondAndThird);

18

.NETコンパイラプラットフォーム( "Roslyn")の言語機能の実装ステータスを見ると、C#6.0ではこれが計画された機能であることがはっきりとわかるので、次のリリースでは通常の方法で実行できます。

バイナリリテラルステータス


3
合格しましたか?ブログで取り上げられているすべての機能が実際にVisual Studio 2015リリースになったわけではありません。
大佐パニック

4
@ColonelPanic- Danationは「C#7のリストに載っている」と指摘-github.com/dotnet/roslyn/issues/2136
Wai Ha Lee

3
string sTable="static class BinaryTable\r\n{";
string stemp = "";
for (int i = 0; i < 256; i++)
{
stemp = System.Convert.ToString(i, 2);
while(stemp.Length<8) stemp = "0" + stemp;
sTable += "\tconst char nb" + stemp + "=" + i.ToString() + ";\r\n";
}
sTable += "}";
Clipboard.Clear();
Clipboard.SetText ( sTable);
MessageBox.Show(sTable);

これを使用して、8ビットバイナリの場合、これを使用して静的クラスを作成し、それをクリップボードに配置します。次に、プロジェクトに貼り付けられ、[使用]セクションに追加されるため、nb001010を持つものはすべて、テーブルから取り出されます最小限の静的ですが、それでも... PICグラフィックコーディングの多くにC#を使用し、Hi-Tech Cでは0b101010を多く使用しています

-コード出力からのサンプル-

static class BinaryTable
{   const char nb00000000=0;
    const char nb00000001=1;
    const char nb00000010=2;
    const char nb00000011=3;
    const char nb00000100=4;
//etc, etc, etc, etc, etc, etc, etc, 
}

:-)ニール


3

バイナリリテラル機能はC#6.0とVisual Studio 2015では実装されていませんでしたが、2016年3月30日、Microsoftはバイナリリテラルを使用できるVisual Studio '15' Previewの新バージョンを発表しました。

桁区切り文字には、1つまたは複数のアンダースコア(_)文字を使用できます。したがって、コードスニペットは次のようになります。

int x           = 0b10___10_0__________________00; //binary value of 80
int SeventyFive = 0B100_________1011; //binary value of 75

WriteLine($" {x} \n {SeventyFive}");

上記のコードスニペットに示すように、0bと0Bのいずれかを使用できます。

桁区切り記号を使用したくない場合は、以下のコードスニペットのように、桁区切り記号なしで使用できます。

int x           = 0b1010000; //binary value of 80
int SeventyFive = 0B1001011; //binary value of 75

WriteLine($" {x} \n {SeventyFive}");

2

Literalを使用することは不可能ですが、BitConverterも解決策になる可能性がありますか?


BitConverterはマシンエンディアンであるため、少し注意が必要です。標準のIntelでは、これはリトルエンディアンを意味します。ほとんどの人は困難リトルエンディアンリテラルを読んで...持っている
マルクGravell

1
痛い、私はいつも私がいつも気付いていたが、BitConverterを使用しなかった理由を覚えています...
Michael Stum

4
BitConverterにはフィールドBitConverter.IsLittleEndianがあり、ホストマシンがリトルエンディアンでないかどうかをテスト(およびバッファーを反転)するために使用できます。
フォクシー'19

1

文字列解析ソリューションが最も一般的ですが、文字列の解析は状況によっては大きなパフォーマンスヒットになる可能性があるため、私はそれが好きではありません。

ある種のビットフィールドまたはバイナリマスクが必要な場合は、次のように記述します

長いビットマスク= 1011001;

以降

int bit5 = BitField.GetBit(bitMask、5);

または

bool flag5 = BitField.GetFlag(bitMask、5); `

BitFieldクラスは

public static class BitField
{
    public static int GetBit(int bitField, int index)
    {
        return (bitField / (int)Math.Pow(10, index)) % 10;
    }

    public static bool GetFlag(int bitField, int index)
    {
        return GetBit(bitField, index) == 1;
    }
}

4
ああ。列挙型を使用しないのはなぜですか?ont 1000を使用して1-0-0-0を表すと、問題が発生します。
クレメント


0

基本的に、答えはノーだと思います。簡単な方法はありません。10進数または16進数の定数を使用してください-それらは単純で明確です。@RoyTinkersの回答も良いです-コメントを使用してください。

int someHexFlag = 0x010; // 000000010000
int someDecFlag = 8;     // 000000001000

ここでの他の回答はいくつかの有用な作業(ラウンド)を示していますが、単純な回答よりも優れているとは思いません。C#言語の設計者は、おそらく '0b'プレフィックスは不要だと考えていました。HEXはバイナリに簡単に変換でき、ほとんどのプログラマーはDECで0〜8に相当するものを知っている必要があります。

また、デバッガで値を調べるとき、それらはHEXまたはDECで表示されます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.