C # Binärliterale

186

Gibt es eine Möglichkeit, binäre Literale in C # zu schreiben, z. B. hexadezimal 0x voranzustellen? 0b funktioniert nicht.

Wenn nicht, wie geht das einfach? Eine Art String-Konvertierung?

toxvaerd
quelle
2
Verwenden Sie Konstanten und geben Sie ihnen Eigennamen. Dann sollte die Tatsache, dass Sie sie dezimal schreiben müssen, keine Rolle spielen. Persönlich würde ich lieber lesen if (a == MaskForModemIOEnabled)alsif (a == 0b100101)
Lasse V. Karlsen
1
Noch ein Hinweis: Wenn Sie diesen Beitrag gefunden haben, weil Sie ein Bitfeld möchten, berücksichtigen Sie bitte das Flags-Attribut: msdn.microsoft.com/en-us/library/cc138362.aspx#sectionToggle0
toxvaerd
16
Beides sehr gute Ratschläge, außer bei der Definition der genannten Bitfelder, bei denen diese benannten konstanten Definitionen mit einem binären Literal leichter zu lesen und zu schreiben sind. [Flags] enum Menge {Keine = 0, Eins = 1, Einige = 0b10, Meist = 0b100, Alle = 0b111}
brianary
1
Für Roslyn ist die Unterstützung von binären Literalen geplant .
Joe White
Es wird in C # 6.0 immer noch nicht unterstützt, oder? Ich kann keine binären Literale in vs2015 verwenden: /
anhoppe

Antworten:

145

C # 7.0 unterstützt binäre Literale (und optionale Zifferntrennzeichen über Unterstriche).

Ein Beispiel:

int myValue = 0b0010_0110_0000_0011;

Weitere Informationen finden Sie auch auf der Roslyn GitHub-Seite .

BTownTKD
quelle
3
@ D.Singh Ich sehe es jetzt auf der C # 7 Liste. github.com/dotnet/roslyn/issues/2136
Danation
9
Süss! Funktioniert hervorragend in VS2017 / C # 7.
STLDev
1
Es ist hilfreich, sich daran zu erinnern, dass die binären Literale von C # Big-Endian sind, aber auf x86-Ganzzahlen Little-Endian sind und daher Int16 = 0b0010_0110_0000_0011als { 0b0000_0011, 0b0010_0110 }- verwirrend gespeichert werden .
Dai
1
@Dai das ist nicht anders als Hex-Literale. Mit anderen Worten, alle Konstanten sind Big Endian, aber Little Endian auf Intel / AMD und den meisten ARMs gespeichert. 0xDEADBEEFwird gespeichert als0xEF 0xBE 0xAD 0xDE
Cole Johnson
168

Aktualisieren

C # 7.0 hat jetzt binäre Literale, was großartig ist.

[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
}

Ursprünglicher Beitrag

Da sich das Thema anscheinend darauf konzentriert hat, bitbasierte Flag-Werte in Aufzählungen zu deklarieren, hielt ich es für sinnvoll, auf einen praktischen Trick für diese Art von Dingen hinzuweisen. Mit dem Linksverschiebungsoperator ( <<) können Sie ein bisschen an eine bestimmte Binärposition drücken. Kombinieren Sie dies mit der Möglichkeit, Enum-Werte in Bezug auf andere Werte in derselben Klasse zu deklarieren, und Sie haben eine sehr einfach zu lesende deklarative Syntax für Bit-Flag-Enums.

[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
}
StriplingWarrior
quelle
26
@ColeJohnson: Viele Entwickler bevorzugen das. Ich bin nicht so gut darin, Hex in meinem Kopf zu konvertieren wie manche Entwickler, und manchmal ist es am besten, auf den kleinsten gemeinsamen Nenner zu achten.
StriplingWarrior
2
Ich denke, dies ist der effektivste Weg, da Aufzählungen als Konstanten erstellt werden. Mit dem optionalen Attribut [Flags] können sie in bitweisen Operationen verwendet werden (nicht direkt mit der Frage verbunden, aber besonders nützlich bei der Beschreibung von Binärliteralen). Eine weitere interessante Möglichkeit besteht darin, den Aufzählungstyp als integrierten Typ zu erzwingen (in diesem Beispiel fügen Sie nach 'Tagen' ': Byte' hinzu). siehe eingebaute Typen in bit.ly/MKv42E
Caligari
Das ist eigentlich sehr einfach zu lesen, obwohl das Deklarieren einer 0-Flagge in einer Aufzählung ziemlich schlecht ist
MikeT
5
@MikeT: Können Sie diesen letzten Gedanken näher erläutern (oder einen ausführlichen Link bereitstellen)? Ich deklariere oft Aufzählungen, die mit "1" beginnen, weil ich erkennen und schnell ausfallen möchte, wenn ein Wert einfach nie initialisiert wurde. Es gibt jedoch Situationen, in denen ein Standardwert tatsächlich Sinn macht, und ich würde denken, dass das Hinzufügen eines Namens für diesen Wert nichts Falsches wäre.
StriplingWarrior
3
@MikeT Von ca1008 : "Wenn eine Aufzählung, auf die das FlagsAttribute angewendet wird, ein Element mit dem Wert Null definiert, sollte der Name 'Keine' lauten, um anzuzeigen, dass in der Aufzählung keine Werte festgelegt wurden." Es ist also durchaus gültig, es als Standardwert hinzuzufügen, wenn es "Keine" heißt. Insgesamt erscheint es mir nur sauberer, wenn der Wert in einem standardmäßig initialisierten Feld tatsächlich einen Namen zum Anzeigen hat.
Nyerguds
115

Ich fürchte, nur Ganzzahl und Hex direkt (ECMA 334v4):

9.4.4.2 Integer-Literale Integer-Literale werden verwendet, um Werte vom Typ int, uint, long und ulong zu schreiben. Ganzzahlige Literale haben zwei mögliche Formen: dezimal und hexadezimal.

Zum Parsen können Sie Folgendes verwenden:

int i = Convert.ToInt32("01101101", 2);
Marc Gravell
quelle
4
Als Aktualisierung dieser Antwort mit den neuesten modernen Informationen (Juli 2014); C # 6.0 führt binäre Literale ein. Siehe meine aktualisierte Antwort wayyyyyy unten ...
BTownTKD
1
@BTownTKD Ihre Antwort ist eigentlich ganz oben :) da es die akzeptierte Antwort ist.
RBT
25

Neben der Antwort von @ StriplingWarrior zu Bit-Flags in Aufzählungen gibt es eine einfache Konvention, die Sie hexadezimal verwenden können, um durch die Bitverschiebungen nach oben zu zählen. Verwenden Sie die Sequenz 1-2-4-8, verschieben Sie eine Spalte nach links und wiederholen Sie den Vorgang.

[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
}

Scannen Sie ab der rechten Spalte nach unten und beachten Sie das Muster 1-2-4-8 (Verschiebung) 1-2-4-8 (Verschiebung) ...


Um die ursprüngliche Frage zu beantworten, stimme ich @ Sahuagins Vorschlag zu, hexadezimale Literale zu verwenden. Wenn Sie häufig genug mit Binärzahlen arbeiten, damit dies ein Problem darstellt, lohnt es sich, sich mit Hexadezimal zu beschäftigen.

Wenn Sie Binärzahlen im Quellcode sehen müssen, schlage ich vor, Kommentare mit Binärliteralen wie oben hinzuzufügen.

Roy Tinker
quelle
23

Sie können jederzeit Quasi-Literale erstellen, Konstanten, die den gewünschten Wert enthalten:

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

Wenn Sie sie häufig verwenden, können Sie sie zur Wiederverwendung in eine statische Klasse einschließen.

Wenn Sie jedoch eine Semantik haben, die mit den Bits verknüpft ist (zur Kompilierungszeit bekannt), würde ich empfehlen, stattdessen eine Aufzählung zu verwenden:

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

Wenn Sie sich den Implementierungsstatus der Sprachfunktionen der .NET Compiler-Plattform ("Roslyn") ansehen, können Sie deutlich erkennen, dass dies in C # 6.0 eine geplante Funktion ist. In der nächsten Version können wir dies also auf die übliche Weise tun.

Binärer Literalstatus

totymedli
quelle
3
Ist es passiert? Nicht alle Funktionen, über die gebloggt wurde, wurden tatsächlich in Visual Studio 2015 veröffentlicht.
Colonel Panic
4
@ColonelPanic - Danation weist darauf hin, dass es "jetzt auf der C # 7-Liste" steht - 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);

Wenn ich dies für 8-Bit-Binärdateien verwende, erstelle ich damit eine statische Klasse und füge sie in die Zwischenablage ein. Dann wird sie in das Projekt eingefügt und dem Abschnitt "Verwenden" hinzugefügt, sodass alles mit nb001010 aus einer Tabelle entfernt wird am wenigsten statisch, aber immer noch ... Ich verwende C # für viele PIC-Grafikcodierungen und verwende 0b101010 häufig in Hi-Tech C.

- Beispiel aus Code outpt--

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, 
}

:-) NEAL

Neal
quelle
3

Die Funktion für binäre Literale wurde in C # 6.0 und Visual Studio 2015 nicht implementiert. Am 30. März 2016 kündigte Microsoft die neue Version von Visual Studio '15' Preview an, mit der wir binäre Literale verwenden können.

Wir können ein oder mehrere Unterstriche (_) für Zifferntrennzeichen verwenden. Das Code-Snippet würde also ungefähr so ​​aussehen:

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

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

und wir können entweder 0b oder 0B verwenden, wie im obigen Codeausschnitt gezeigt.

Wenn Sie kein Zifferntrennzeichen verwenden möchten, können Sie es ohne Zifferntrennzeichen wie im folgenden Codeausschnitt verwenden

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

WriteLine($" {x} \n {SeventyFive}");
Banketeshvar Narayan
quelle
2

Ein BitConverter ist zwar nicht mit einem Literal möglich, kann aber auch eine Lösung sein?

Michael Stum
quelle
BitConverter wird etwas knifflig, weil es maschinenendisch ist. und auf Ihrem Standard-Intel bedeutet das Little-Endian. Die meisten Menschen haben Schwierigkeiten, Little-Endian-Literale zu lesen ...
Marc Gravell
1
Autsch, jetzt erinnere ich mich, warum ich den BitConverter immer kannte, aber nie benutzte ...
Michael Stum
4
BitConverter hat das Feld BitConverter.IsLittleEndian, mit dem Sie testen (und einen Puffer umkehren) können, wenn der Host-Computer nicht Little Endian ist.
Foxy
1

Obwohl die String-Parsing-Lösung die beliebteste ist, gefällt sie mir nicht, da das Parsen von Strings in manchen Situationen ein großer Leistungseinbruch sein kann.

Wenn eine Art Bitfeld oder Binärmaske benötigt wird, schreibe ich sie lieber so

lange Bitmaske = 1011001;

Und später

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

Oder

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

Wo sich die BitField-Klasse befindet

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;
    }
}
Dmitry Tashkinov
quelle
4
Yuck. Warum nicht einfach Aufzählungen verwenden? Die Verwendung von tausend als 1-0-0-0 bedeutet nur Ärger.
Clément
1

Sie können 0b000001seit Visual Studio 2017 (C # 7.0) verwenden

Xiaoyuvax
quelle
0

Grundsätzlich denke ich, die Antwort ist NEIN, es gibt keinen einfachen Weg. Verwenden Sie Dezimal- oder Hexadezimalkonstanten - sie sind einfach und klar. @ RoyTinkers Antwort ist auch gut - benutze einen Kommentar.

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

Die anderen Antworten hier bieten einige nützliche Arbeitsrunden, aber ich denke, sie sind nicht besser als die einfache Antwort. C # -Sprachendesigner hielten ein Präfix '0b' wahrscheinlich für unnötig. HEX lässt sich leicht in Binärdateien konvertieren, und die meisten Programmierer müssen die DEC-Äquivalente von 0-8 sowieso kennen.

Wenn Sie Werte im Debugger untersuchen, werden sie mit HEX oder DEC angezeigt.

RaoulRubin
quelle