Littéraux binaires C #

192

Existe-t-il un moyen d'écrire des littéraux binaires en C #, comme préfixer hexadécimal avec 0x? 0b ne fonctionne pas.

Sinon, quelle est la manière la plus simple de le faire? Une sorte de conversion de chaîne?

toxvaerd
la source
2
Utilisez des constantes et donnez-leur des noms propres, le fait que vous deviez les écrire en décimal ne devrait pas avoir d'importance. Personnellement, je voudrais lire if (a == MaskForModemIOEnabled)plutôt queif (a == 0b100101)
Lasse V. Karlsen
2
Une autre note: Si vous avez trouvé ce message parce que vous voulez un champ de bits, veuillez considérer l'attribut flags
toxvaerd
17
Ces deux très bons conseils, sauf lors de la définition desdits champs de bits, où ces définitions de constantes nommées peuvent être plus faciles à lire et à écrire avec un littéral binaire. [Flags] enum Quantity {None = 0, One = 1, Some = 0b10, Most = 0b100, All = 0b111}
brianary
1
Pour ce que ça vaut, la prise en charge des littéraux binaires est prévue pour Roslyn .
Joe White
Il n'est toujours pas pris en charge dans C # 6.0, non? Impossible d'utiliser les littéraux binaires dans vs2015: /
anhoppe

Réponses:

153

C # 7.0 prend en charge les littéraux binaires (et les séparateurs de chiffres facultatifs via des caractères de soulignement).

Un exemple:

int myValue = 0b0010_0110_0000_0011;

Vous pouvez également trouver plus d'informations sur la page Roslyn GitHub .

BTownTKD
la source
3
@ D.Singh Je le vois maintenant sur la liste C # 7. github.com/dotnet/roslyn/issues/2136
Danation
9
Sucré! Fonctionne très bien dans VS2017 / C # 7.
STLDev
1
Il est utile de se rappeler que les littéraux binaires de C # sont big-endian, mais sur x86, les entiers sont little-endian, donc Int16 = 0b0010_0110_0000_0011seront stockés comme { 0b0000_0011, 0b0010_0110 }- déroutant.
Dai
1
@Dai ce n'est pas différent des littéraux hexadécimaux. En d'autres termes, toutes les constantes sont big endian, mais stockées little endian sur Intel / AMD et la plupart des ARM. 0xDEADBEEFsera stocké comme0xEF 0xBE 0xAD 0xDE
Cole Johnson le
173

Mise à jour

C # 7.0 a maintenant des littéraux binaires, ce qui est génial.

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

Message original

Puisque le sujet semble s'être tourné vers la déclaration de valeurs d'indicateur basées sur les bits dans les énumérations, j'ai pensé qu'il serait intéressant de souligner une astuce pratique pour ce genre de chose. L'opérateur de décalage à gauche ( <<) vous permettra de pousser un peu vers une position binaire spécifique. Combinez cela avec la possibilité de déclarer des valeurs d'énumération en termes d'autres valeurs dans la même classe, et vous avez une syntaxe déclarative très facile à lire pour les énumérations d'indicateurs de bits.

[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
}
StriplingGuerrier
la source
27
@ColeJohnson: De nombreux développeurs préfèrent cela. Je ne suis pas aussi doué pour convertir l'hexagone dans ma tête que certains développeurs, et parfois il est préférable de prendre en compte le plus petit dénominateur commun.
StriplingWarrior
2
Je pense que c'est le moyen le plus efficace puisque les énumérations sont construites sous forme de constantes. Avec l'attribut facultatif [Flags], ils peuvent être utilisés dans des opérations au niveau du bit (non directement liées à la question, mais particulièrement utiles pour décrire des littéraux binaires). Une autre possibilité intéressante est de forcer le type enum comme type intégré (dans cet exemple, ajoutez ': byte' après 'Days'); voir les types intégrés
caligari
C'est en fait très facile à lire, bien que déclarer un drapeau 0 sur un Enum soit une assez mauvaise pratique
MikeT
6
@MikeT: Pouvez-vous élaborer (ou fournir un lien qui élabore) sur cette dernière pensée? Je déclare souvent des énumérations qui commencent par "1" parce que je veux pouvoir détecter et échouer rapidement lorsqu'une valeur n'a tout simplement jamais été initialisée. Mais il y a des situations où une valeur par défaut a du sens, et je pense qu'il n'y aurait rien de mal à ajouter un nom pour cette valeur.
StriplingWarrior
3
@MikeT From ca1008 : "Si une énumération qui a le FlagsAttribute appliqué définit un membre de valeur zéro, son nom doit être 'None' pour indiquer qu'aucune valeur n'a été définie dans l'énumération." Il est donc parfaitement valable de l'ajouter pour servir de valeur par défaut, s'il s'appelle "Aucun". Dans l'ensemble, cela me semble plus propre si la valeur d'un champ initialisé par défaut a réellement un nom à afficher.
Nyerguds
115

Seuls les nombres entiers et hexadécimaux directement, j'ai peur (ECMA 334v4):

9.4.4.2 Littéraux entiers Les littéraux entiers sont utilisés pour écrire des valeurs de types int, uint, long et ulong. Les littéraux entiers ont deux formes possibles: décimale et hexadécimale.

Pour analyser, vous pouvez utiliser:

int i = Convert.ToInt32("01101101", 2);
Marc Gravell
la source
4
En tant que mise à jour de cette réponse, avec les dernières informations modernes de pointe (juillet 2014); C # 6.0 introduit les littéraux binaires. Voir ma réponse mise à jour wayyyyyy en bas ...
BTownTKD
2
@BTownTKD votre réponse est en fait en haut :) car c'est la réponse acceptée.
RBT
26

En plus de la réponse de @ StriplingWarrior sur les indicateurs de bits dans les énumérations, il existe une convention simple que vous pouvez utiliser en hexadécimal pour compter vers le haut à travers les décalages de bits. Utilisez la séquence 1-2-4-8, déplacez une colonne vers la gauche et répétez.

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

Balayez vers le bas en commençant par la colonne de droite et notez le motif 1-2-4-8 (décalage) 1-2-4-8 (décalage) ...


Pour répondre à la question initiale, j'appuie la suggestion de @ Sahuagin d'utiliser des littéraux hexadécimaux. Si vous travaillez assez souvent avec des nombres binaires pour que cela soit un problème, cela vaut la peine de maîtriser l'hexadécimal.

Si vous avez besoin de voir des nombres binaires dans le code source, je suggère d'ajouter des commentaires avec des littéraux binaires comme je l'ai fait ci-dessus.

Roy Tinker
la source
23

Vous pouvez toujours créer des quasi-littéraux, des constantes qui contiennent la valeur que vous recherchez:

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

Si vous les utilisez souvent, vous pouvez les envelopper dans une classe statique pour les réutiliser.

Cependant, légèrement hors sujet, si vous avez une sémantique associée aux bits (connue au moment de la compilation), je suggérerais d'utiliser un Enum à la place:

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

Si vous regardez l' état d'implémentation des fonctionnalités de langage de la plate-forme du compilateur .NET ("Roslyn"), vous pouvez clairement voir que dans C # 6.0, il s'agit d'une fonctionnalité prévue, donc dans la prochaine version, nous pouvons le faire de la manière habituelle.

Statut littéral binaire

totymedli
la source
3
Cela s'est-il produit? Toutes les fonctionnalités sur lesquelles les blogs ont été publiés n'ont pas été réellement publiées dans Visual Studio 2015.
Colonel Panic
4
@ColonelPanic - Danation souligne qu'il est "sur la liste C # 7 maintenant" - 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);

En utilisant ceci, pour le binaire 8 bits, je l'utilise pour créer une classe statique et la place dans le presse-papiers. Ensuite, elle est collée dans le projet et ajoutée à la section Utilisation, donc tout ce qui contient nb001010 est retiré d'une table moins statique, mais quand même ... j'utilise C # pour beaucoup de codage graphique PIC et j'utilise beaucoup 0b101010 en Hi-Tech C

--échantillon à partir de la sortie de code--

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
la source
3

La fonctionnalité de littéral binaire n'a pas été implémentée dans C # 6.0 et Visual Studio 2015. mais le 30 mars 2016, Microsoft a annoncé la nouvelle version de Visual Studio '15' Preview avec laquelle nous pouvons utiliser des littéraux binaires.

Nous pouvons utiliser un ou plusieurs caractères de soulignement (_) pour les séparateurs de chiffres. donc l'extrait de code ressemblerait à quelque chose comme:

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

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

et nous pouvons utiliser 0b et 0B comme indiqué dans l'extrait de code ci-dessus.

si vous ne voulez pas utiliser de séparateur de chiffres, vous pouvez l'utiliser sans séparateur de chiffres comme ci-dessous l'extrait de code

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

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

Bien qu'il ne soit pas possible d'utiliser un littéral, peut-être qu'un BitConverter peut également être une solution?

Michael Stum
la source
BitConverter devient un peu délicat car il est machine-endian; et sur votre Intel standard, cela signifie petit-boutiste. La plupart des gens ont de la difficulté à lire les littéraux little-endian ...
Marc Gravell
1
Aïe, maintenant je me souviens pourquoi j'ai toujours été au courant mais je n'ai jamais utilisé le BitConverter ...
Michael Stum
4
BitConverter a le champ BitConverter.IsLittleEndian, que vous pouvez utiliser pour tester (et inverser un tampon) si la machine hôte n'est pas peu endian.
foxy
1

Bien que la solution d'analyse de chaîne soit la plus populaire, je ne l'aime pas, car l'analyse de chaîne peut être un grand succès en termes de performances dans certaines situations.

Quand il faut une sorte de champ de bits ou de masque binaire, je préfère l'écrire comme

bitMask long = 1011001;

Et ensuite

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

Ou

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

Où se trouve 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;
    }
}
Dmitry Tashkinov
la source
4
Beurk. Pourquoi ne pas simplement utiliser des énumérations? Utiliser ont mille pour signifier 1-0-0-0 ne demande que des ennuis.
Clément
1

Vous pouvez utiliser 0b000001depuis Visual Studio 2017 (C # 7.0)

Xiaoyuvax
la source
0

Fondamentalement, je pense que la réponse est NON, il n'y a pas de moyen facile. Utilisez des constantes décimales ou hexadécimales - elles sont simples et claires. La réponse @RoyTinkers est également bonne - utilisez un commentaire.

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

Les autres réponses ici présentent plusieurs séries de travaux utiles, mais je pense qu'elles ne sont pas meilleures que la réponse simple. Les concepteurs de langage C # ont probablement considéré un préfixe «0b» inutile. HEX est facile à convertir en binaire et la plupart des programmeurs devront de toute façon connaître les équivalents DEC de 0 à 8.

De plus, lors de l'examen des valeurs dans le débogueur, elles seront affichées avec HEX ou DEC.

RaoulRubin
la source