Letterali binari C #


187

C'è un modo per scrivere letterali binari in C #, come il prefisso esadecimale con 0x? 0b non funziona.

In caso contrario, qual è un modo semplice per farlo? Qualche tipo di conversione di stringa?


2
Usa le costanti e dai loro i nomi propri, quindi il fatto che devi scriverli in decimale non dovrebbe importare. Personalmente vorrei leggere if (a == MaskForModemIOEnabled)piuttosto cheif (a == 0b100101)
Lasse V. Karlsen,

2
Un'altra nota: Se hai trovato questo post, perché si desidera un campo di bit, si prega di considerare il flag-attribute: msdn.microsoft.com/en-us/library/cc138362.aspx#sectionToggle0
toxvaerd

17
Entrambi ottimi consigli, tranne quando si definiscono detti bitfield, dove queste definizioni costanti nominate possono essere più facili da leggere e scrivere con un valore letterale binario. [Flags] enum Quantity {None = 0, One = 1, Some = 0b10, Most = 0b100, All = 0b111}
brianary

1
Per quello che vale, è previsto il supporto per i letterali binari per Roslyn .
Joe White,

Non è ancora supportato in C # 6.0, giusto? Impossibile usare i letterali binari in vs2015: /
anhoppe il

Risposte:


146

C # 7.0 supporta valori letterali binari (e separatori di cifre opzionali tramite caratteri di sottolineatura).

Un esempio:

int myValue = 0b0010_0110_0000_0011;

Puoi anche trovare maggiori informazioni sulla pagina Roslyn GitHub .


3
@ D.Singh Lo vedo ora nell'elenco C # 7. github.com/dotnet/roslyn/issues/2136
Danation

9
Dolce! Funziona alla grande in VS2017 / C # 7.
STLDev,

1
Aiuta a ricordare che i letterali binari di C # sono big-endian, ma su interi x86 sono little-endian, quindi Int16 = 0b0010_0110_0000_0011verranno memorizzati come { 0b0000_0011, 0b0010_0110 }- confusi.
Dai,

1
@Dai non è diverso dai letterali esadecimali. In altre parole, tutte le costanti sono big endian, ma memorizzate little endian su Intel / AMD e la maggior parte degli ARM. 0xDEADBEEFsarà memorizzato come0xEF 0xBE 0xAD 0xDE
Cole Johnson il

170

Aggiornare

C # 7.0 ora ha letterali binari, il che è fantastico.

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

Posta originale

Dato che l'argomento sembra essersi rivolto alla dichiarazione di valori di flag basati su bit negli enum, ho pensato che valesse la pena sottolineare un trucco utile per questo genere di cose. L'operatore di spostamento a sinistra ( <<) ti permetterà di spingere un po 'verso una posizione binaria specifica. Combinalo con la capacità di dichiarare i valori enum in termini di altri valori nella stessa classe e avrai una sintassi dichiarativa molto facile da leggere per gli enum di flag di bit.

[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: molti sviluppatori lo preferiscono. Non sono bravo a convertire hex nella mia testa come lo sono alcuni sviluppatori, e talvolta è meglio provvedere al minimo comune denominatore.
StriplingWarrior il

2
Penso che questo sia il modo più efficace poiché gli enum sono costruiti come costanti. Con l'attributo facoltativo [Flags] possono essere utilizzati in operazioni bit a bit (non direttamente correlate alla domanda, ma particolarmente utili quando si descrivono letterali binari). Un'altra possibilità interessante è forzare il tipo enum come tipo incorporato (in questo esempio aggiungere ': byte' dopo 'Days'); vedi i tipi integrati
caligari

Questo è in realtà molto facile da leggere, anche se dichiarare un flag 0 su un Enum è una pratica piuttosto negativa
MikeT

5
@MikeT: Puoi elaborare (o fornire un link che elabora) su quell'ultimo pensiero? Dichiaro spesso enumerazioni che iniziano con "1" perché voglio essere in grado di rilevare e fallire velocemente quando un valore non è mai stato inizializzato. Ma ci sono alcune situazioni in cui un valore predefinito ha effettivamente senso e penso che non ci sarebbe nulla di sbagliato nell'aggiungere un nome per quel valore.
StriplingWarrior,

3
@MikeT Da ca1008 : "Se un'enumerazione a cui è applicato FlagsAttribute definisce un membro a valore zero, il suo nome dovrebbe essere 'Nessuno' per indicare che non sono stati impostati valori nell'enumerazione." Quindi è perfettamente valido aggiungerlo per servire come valore predefinito, se si chiama "Nessuno". Nel complesso mi sembra più pulito se il valore in un campo inizializzato come predefinito ha effettivamente un nome da mostrare.
Nyerguds

115

Ho solo direttamente numeri interi ed esadecimali, temo (ECMA 334v4):

9.4.4.2 Letterali interi I letterali interi vengono utilizzati per scrivere valori di tipi int, uint, long e ulong. I letterali interi hanno due forme possibili: decimale ed esadecimale.

Per analizzare, puoi usare:

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

4
Come aggiornamento a questa risposta, con le ultime informazioni moderne all'avanguardia (luglio 2014); C # 6.0 introduce letterali binari. Vedi la mia risposta aggiornata wayyyyyy in basso ...
BTownTKD

1
@BTownTKD la tua risposta è in realtà in alto :) in quanto è la risposta accettata.
RBT,

25

Aggiungendo alla risposta di @ StriplingWarrior sulle flag di bit negli enum, c'è una semplice convenzione che puoi usare in esadecimale per contare verso l'alto attraverso i bit shift. Utilizzare la sequenza 1-2-4-8, spostare una colonna a sinistra e ripetere.

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

Scorri verso il basso a partire dalla colonna di destra e osserva il modello 1-2-4-8 (spostamento) 1-2-4-8 (spostamento) ...


Per rispondere alla domanda originale, secondo il suggerimento di @ Sahuagin di usare letterali esadecimali. Se stai lavorando con numeri binari abbastanza spesso da essere fonte di preoccupazione, vale la pena dedicare del tempo all'esadecimale.

Se hai bisogno di vedere i numeri binari nel codice sorgente, ti suggerisco di aggiungere commenti con valori letterali binari come ho sopra.


23

Puoi sempre creare quasi-letterali, costanti che contengono il valore che stai cercando:

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

Se li usi spesso, puoi avvolgerli in una classe statica per riutilizzarli.

Tuttavia, leggermente fuori tema, se hai qualche semantica associata ai bit (conosciuta al momento della compilazione), suggerirei invece di usare un Enum:

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

18

Se osservi lo stato di implementazione della funzionalità linguistica della piattaforma di compilatore .NET ("Roslyn") puoi vedere chiaramente che in C # 6.0 questa è una funzionalità pianificata, quindi nella prossima versione possiamo farlo nel solito modo.

Stato letterale binario


3
È successo? Non tutte le funzionalità di cui è stato scritto il blog hanno effettivamente rilasciato la versione di Visual Studio 2015.
Colonnello Panic,

4
@ColonelPanic - Danation sottolinea che è "nella lista C # 7 ora" - 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);

Usando questo, per binario a 8 bit, lo uso per creare una classe statica e la inserisce negli Appunti. Quindi viene incollata nel progetto e aggiunta alla sezione Utilizzo, quindi qualsiasi cosa con nb001010 viene estratta da una tabella, in meno statico, ma comunque ... Uso C # per molta codifica grafica PIC e uso 0b101010 molto in Hi-Tech C

--campione dall'output del codice--

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


3

La funzionalità letterale binaria non è stata implementata in C # 6.0 e Visual Studio 2015. Ma il 30 marzo 2016 Microsoft ha annunciato la nuova versione dell'anteprima '15' di Visual Studio con la quale è possibile utilizzare valori letterali binari.

Possiamo usare uno o più caratteri di sottolineatura (_) per i separatori di cifre. quindi lo snippet di codice sarebbe simile a:

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

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

e possiamo usare 0b e 0B come mostrato nello snippet di codice sopra riportato.

se non si desidera utilizzare il separatore di cifre, è possibile utilizzarlo senza il separatore di cifre come sotto lo snippet di codice

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

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

2

Sebbene non sia possibile utilizzare un valore letterale, forse un BitConverter può anche essere una soluzione?


BitConverter diventa un po 'complicato perché è end-machine; e sul tuo Intel standard, ciò significa little-endian. Molte persone hanno difficoltà a leggere letterali little-endian ...
Marc Gravell

1
Ouch, ora ricordo perché ero sempre a conoscenza ma non ho mai usato BitConverter ...
Michael Stum

4
BitConverter ha il campo BitConverter.IsLittleEndian, che è possibile utilizzare per testare (e invertire un buffer) se la macchina host non è poco endian.
Foxy,

1

Sebbene la soluzione di analisi delle stringhe sia la più popolare, non mi piace, perché l'analisi delle stringhe può essere un grande successo in alcune situazioni.

Quando c'è bisogno di una specie di bitfield o maschera binaria, preferirei scriverlo come

long bitMask = 1011001;

E più tardi

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

O

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

Dove si trova la classe 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
Che schifo. Perché non usare solo enums? Usare ont mila per significare 1-0-0-0 è solo chiedere problemi.
Clément,


0

Fondamentalmente, penso che la risposta sia NO, non esiste un modo semplice. Usa le costanti decimali o esadecimali: sono semplici e chiare. Anche la risposta di @RoyTinkers è buona: usa un commento.

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

Le altre risposte qui presentano alcuni utili round di lavoro, ma penso che non siano migliori della semplice risposta. I progettisti del linguaggio C # probabilmente hanno ritenuto superfluo un prefisso "0b". HEX è facile da convertire in binario e la maggior parte dei programmatori dovrà comunque conoscere gli equivalenti DEC di 0-8.

Inoltre, quando si esaminano i valori nel debugger, verranno visualizzati HEX o DEC.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.