C # бінарні літерали


187

Чи є спосіб записати двійкові літерали на C #, як префіксація шістнадцяткової з 0x? 0b не працює.

Якщо ні, то який простий спосіб це зробити? Якийсь рядок перетворення?


2
Використовуйте константи і дайте їм належні імена, тоді факт, що ви повинні виписати їх у десятковій формі, не має значення. Особисто я хотів би прочитати, if (a == MaskForModemIOEnabled)а неif (a == 0b100101)
Лассе В. Карлсен

2
Ще одна примітка: Якщо ви знайшли цю публікацію, тому що хочете трохи поля, будь ласка, врахуйте прапорці-атрибут: msdn.microsoft.com/en-us/library/cc138362.aspx#sectionToggle0
toxvaerd

17
Обидва дуже хороші поради, за винятком випадків визначення зазначених біт-полів, де ці названі постійні визначення можуть бути простішими для читання та запису з двійковим буквалом. [Прапори] enum Кількість {None = 0, One = 1, Some = 0b10, Most = 0b100, All = 0b111}
Brianary

1
Для чого це варто, Рослину планується підтримка бінарних літералів .
Джо Уайт

Це все ще не підтримується в C # 6.0, правда? Неможливо використовувати бінарні літерали в vs2015: /
anhoppe

Відповіді:


146

C # 7.0 підтримує двійкові літерали (та необов'язкові розділові знаки через символи підкреслення).

Приклад:

int myValue = 0b0010_0110_0000_0011;

Ви також можете знайти більше інформації на сторінці Roslyn GitHub .


3
@ D.Singh Я зараз бачу це у списку C # 7. github.com/dotnet/roslyn/isissue/2136
Данація

9
Солодке! Чудово працює у VS2017 / C №7.
СТЛДєв

1
Це допомагає пам’ятати, що Бінарні літерали C # 'є великим ендіаном, але на x86 цілі числа є мало-ендіанськими, тому Int16 = 0b0010_0110_0000_0011зберігатимуться як { 0b0000_0011, 0b0010_0110 }- заплутані.
Дай

1
@Dai, що не відрізняється від шістнадцяткових літералів. Іншими словами, всі константи є великими ендіанами, але зберігаються мало ендіанів в Intel / AMD та більшості ARM. 0xDEADBEEFбуде зберігатися як0xEF 0xBE 0xAD 0xDE
Cole Johnson

170

Оновлення

У 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: Багато розробників вважають за краще це. Я не так добре перетворюю шістнадцяткову голову, як деякі розробники, і іноді найкраще задовольнити найнижчий загальний знаменник.
Стриптинг-воїн

2
Я думаю, що це найефективніший спосіб, оскільки перерахунки будуються як константи. За допомогою необов'язкового атрибута [Flags] вони можуть використовуватися в побітових операціях (не пов'язаних безпосередньо з питанням, але особливо корисними при описі двійкових літералів). Ще одна цікава можливість - примусити тип enum як вбудований тип (у цьому прикладі додати ': byte' після 'Days'); дивіться вбудовані типи в bit.ly/MKv42E
caligari

Це насправді дуже легко читати, хоча оголошення прапора 0 на Enum є досить поганою практикою
MikeT

5
@MikeT: Чи можете ви детально (або надати посилання, що розробляє) останню думку? Я часто декларую перерахунки, які починаються з "1", тому що я хочу бути здатним виявляти та швидко виходити з ладу, коли значення просто не було ініціалізовано. Але є деякі ситуації, коли значення за замовчуванням насправді має сенс, і я думаю, що не було б нічого поганого з додаванням імені для цього значення.
Стриптинг-воїн

3
@MikeT Від ca1008 : "Якщо перерахунок із застосованим FlagsAttribute визначає нульовий член, його ім'я має бути" None ", щоб вказати, що в перерахунку не встановлено жодних значень." Тож цілком справедливо додати його як значення за замовчуванням, якщо воно називається "None". В цілому мені просто здається більш зрозумілим, якщо значення в ініціалізованому полі за замовчуванням насправді має вказати ім'я.
Nyerguds

115

Боюся лише цілих чи шестнадцяткових (ECMA 334v4):

9.4.4.2 Цілі літерали Цілі літерали використовуються для запису значень типів int, uint, long та ulong. Цілі літерали мають дві можливі форми: десяткову та шістнадцяткову.

Для розбору можна використовувати:

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

4
Як оновлення до цієї відповіді, з найновішою сучасною інформацією (липень 2014 р.); C # 6.0 вводить двійкові літерали. Дивіться мою оновлену відповідь внизу внизу ...
BTownTKD

1
@BTownTKD ваша відповідь насправді вгорі :), як це прийнята відповідь.
RBT

25

Додавши до @ StriplingWarrior відповідь про бітові прапори в перерахунках, є проста конвенція, яку ви можете використовувати в шістнадцятковій формі для підрахунку вгору через зсуви бітів. Скористайтеся послідовністю 1-2-4-8, перемістіть один стовпчик вліво і повторіть.

[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 (зміна) ...


Щоб відповісти на початкове запитання, я друге пропозицію @ Сахуагіна використовувати шістнадцяткові літерали. Якщо ви працюєте з двійковими числами досить часто, щоб це викликало занепокоєння, варто витратити час на отримання шестинадцяткової повіси.

Якщо вам потрібно побачити двійкові числа у вихідному коді, я пропоную додати коментарі з бінарними буквами, як у мене вище.


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 Compiler Platform ("Roslyn"), ви можете чітко побачити, що в C # 6.0 це запланована функція, тому в наступному випуску ми можемо це зробити звичайним способом.

Бінарний буквальний статус


3
Це сталося? Не всі функції, про які ведеться блог, насправді зробили випуск Visual Studio 2015.
Полковник Паніка

4
@ColonelPanic - Danation зазначає, що зараз "у списку C # 7" - github.com/dotnet/roslyn/isissue/2136
Вай Ха Лі

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 виймається з таблиці, в принаймні статичний, але все-таки ... Я використовую C # для багатьох кодувань графіки PIC і дуже часто використовую 0b101010 в Hi-Tech C

- зразок з вихідного коду--

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., але 30 березня 2016 року Microsoft оголосила про нову версію Visual Studio '15' Preview, завдяки якій ми можемо використовувати бінарні літерали.

Ми можемо використовувати один або кілька символів підкреслення (_) для розділювачів цифр. так фрагмент коду виглядатиме приблизно так:

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, це означає, що ендіан. У більшості людей виникають труднощі з читанням
малоепіанських

1
О, тепер я пам'ятаю, чому я завжди був у курсі, але ніколи не використовував BitConverter ...
Майкл Стум

4
BitConverter має поле BitConverter.IsLittleEndian, яке ви можете використовувати для тестування (і повернення буфера), якщо хост-машина не мало ендіан.
foxy

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
Гидота. Чому б просто не використати переписки? Використання тисяч тисяч для позначення 1-0-0-0 - це просто прохання про проблеми.
Clément


0

В основному, я думаю, що відповідь "НІ", немає простого способу. Використовуйте десяткові або шістнадцяткові константи - вони прості і чіткі. Відповідь @RoyTinkers також хороша - використовуйте коментар.

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

Інші відповіді тут представляють кілька корисних робочих раундів, але я думаю, що вони не кращі, ніж проста відповідь. Дизайнери мови C #, ймовірно, вважали префікс '0b' непотрібним. HEX легко перетворити у бінарний, і більшість програмістів у будь-якому разі повинні знати еквіваленти DEC 0-8.

Також при дослідженні значень у налагоджувачі вони будуть відображатись з HEX або DEC.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.