C # literal biner

187

Apakah ada cara untuk menulis literal biner dalam C #, seperti awalan heksadesimal dengan 0x? 0b tidak berfungsi.

Jika tidak, apa cara mudah untuk melakukannya? Semacam konversi string?

racun
sumber
2
Gunakan konstanta dan beri mereka nama yang tepat, maka fakta bahwa Anda harus menuliskannya dalam desimal tidak masalah. Secara pribadi saya ingin membaca if (a == MaskForModemIOEnabled)daripadaif (a == 0b100101)
Lasse V. Karlsen
2
Catatan lain: Jika Anda menemukan posting ini karena Anda ingin bidang bit, harap pertimbangkan atribut flags: msdn.microsoft.com/en-us/library/cc138362.aspx#sectionToggle0
toxvaerd
17
Keduanya saran yang sangat baik, kecuali ketika mendefinisikan bitfields kata, di mana definisi konstan bernama ini dapat lebih mudah dibaca dan ditulis dengan literal biner. [Bendera] enum Kuantitas {Tidak Ada = 0, Satu = 1, Beberapa = 0b10, Paling = 0b100, Semua = 0b111}
brianary
1
Untuk apa nilainya, dukungan untuk literal biner direncanakan untuk Roslyn .
Joe White
Itu masih tidak didukung di C # 6.0, kan? Tidak dapat menggunakan literal biner di vs2015: /
anhoppe

Jawaban:

146

C # 7.0 mendukung literal biner (dan pemisah digit opsional melalui karakter garis bawah).

Sebuah contoh:

int myValue = 0b0010_0110_0000_0011;

Anda juga dapat menemukan informasi lebih lanjut di halaman Roslyn GitHub .

BTownTKD
sumber
3
@ D.Singh Saya melihatnya di daftar C # 7 sekarang. github.com/dotnet/roslyn/issues/2136
Danation
9
Manis! Bekerja hebat di VS2017 / C # 7.
STLDev
1
Ini membantu untuk mengingat bahwa Binary Literals C # adalah big-endian, tetapi pada x86 integer adalah little-endian, jadi Int16 = 0b0010_0110_0000_0011akan disimpan sebagai { 0b0000_0011, 0b0010_0110 }- membingungkan.
Dai
1
@ Hai itu tidak berbeda dari hex literal. Dengan kata lain, semua konstanta adalah endian besar, tetapi disimpan endian kecil pada Intel / AMD dan sebagian besar ARM. 0xDEADBEEFakan disimpan sebagai0xEF 0xBE 0xAD 0xDE
Cole Johnson
170

Memperbarui

C # 7.0 sekarang memiliki literal biner, yang mengagumkan.

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

Pos Asli

Karena topik tampaknya telah beralih ke mendeklarasikan nilai bendera berbasis bit di enum, saya pikir akan bermanfaat untuk menunjukkan trik yang berguna untuk hal semacam ini. Operator shift kiri ( <<) akan memungkinkan Anda untuk mendorong sedikit ke posisi biner tertentu. Gabungkan itu dengan kemampuan untuk mendeklarasikan nilai enum dalam hal nilai lain di kelas yang sama, dan Anda memiliki sintaks deklaratif yang mudah dibaca untuk bit flag enum.

[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
sumber
26
@ColeJohnson: Banyak pengembang lebih suka itu. Saya tidak sebagus mengkonversi hex di kepala saya seperti beberapa pengembang, dan kadang-kadang lebih baik untuk memenuhi penyebut umum terendah.
StriplingWarrior
2
Saya pikir ini adalah cara paling efektif karena enum dibangun sebagai konstanta. Dengan atribut [Bendera] opsional, mereka dapat digunakan dalam operasi bitwise (tidak terkait langsung dengan pertanyaan, tetapi sangat berguna saat menggambarkan literal biner). Kemungkinan menarik lainnya adalah untuk memaksa tipe enum sebagai tipe bawaan (dalam contoh ini, tambahkan ': byte' setelah 'Days'); lihat tipe bawaan
caligari
Itu sebenarnya sangat mudah dibaca, meskipun menyatakan bendera 0 pada Enum adalah praktik yang cukup buruk
MikeT
5
@ MikeT: Dapatkah Anda menguraikan (atau memberikan tautan yang menguraikan) pemikiran terakhir itu? Saya sering menyatakan enum yang dimulai dengan "1" karena saya ingin dapat mendeteksi dan gagal-cepat ketika suatu nilai tidak pernah diinisialisasi. Tetapi ada beberapa situasi di mana nilai default benar-benar masuk akal, dan saya pikir tidak akan ada salahnya dengan menambahkan nama untuk nilai itu.
StriplingWarrior
3
@MikeT Dari ca1008 : "Jika enumerasi yang menerapkan FlagsAttribute mendefinisikan anggota bernilai nol, namanya harus 'Tidak Ada' untuk menunjukkan bahwa tidak ada nilai yang telah ditetapkan dalam enumerasi." Jadi sangat sah untuk menambahkannya sebagai nilai default, jika itu disebut "Tidak Ada". Secara keseluruhan sepertinya lebih bersih bagi saya jika nilai dalam bidang inisialisasi default sebenarnya memiliki nama untuk ditampilkan.
Nyerguds
115

Hanya integer dan hex secara langsung, saya takut (ECMA 334v4):

9.4.4.2 Integer literals Integer literals digunakan untuk menulis nilai tipe int, uint, long, dan ulong. Literal integer memiliki dua bentuk yang mungkin: desimal dan heksadesimal.

Untuk menguraikan, Anda dapat menggunakan:

int i = Convert.ToInt32("01101101", 2);
Marc Gravell
sumber
4
Sebagai pembaruan untuk jawaban ini, dengan informasi modern mutakhir terbaru (Juli, 2014); C # 6.0 memperkenalkan literal biner. Lihat jawaban saya yang diperbarui wayyyyyy di bagian bawah ...
BTownTKD
1
@BTownTKD jawaban Anda sebenarnya ada di atas :) karena itu adalah jawaban yang diterima.
RBT
25

Menambahkan ke jawaban @ StriplingWarrior tentang flag bit di enums, ada konvensi mudah yang dapat Anda gunakan dalam heksadesimal untuk menghitung ke atas melalui perubahan bit. Gunakan urutan 1-2-4-8, pindahkan satu kolom ke kiri, dan ulangi.

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

Memindai dimulai dengan kolom kanan dan perhatikan pola 1-2-4-8 (shift) 1-2-4-8 (shift) ...


Untuk menjawab pertanyaan awal, saya menyarankan saran kedua @ Sahuagin untuk menggunakan heksadesimal literal. Jika Anda cukup sering menggunakan angka biner untuk masalah ini, ada baiknya Anda memanfaatkan heksadesimal.

Jika Anda perlu melihat angka-angka biner dalam kode sumber, saya sarankan menambahkan komentar dengan literal biner seperti yang saya miliki di atas.

Roy Tinker
sumber
23

Anda selalu dapat membuat kuasi-literal, konstanta yang berisi nilai yang Anda inginkan:

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

Jika Anda sering menggunakannya maka Anda dapat membungkusnya dalam kelas statis untuk digunakan kembali.

Namun, sedikit di luar topik, jika Anda memiliki semantik yang terkait dengan bit (dikenal pada waktu kompilasi) saya akan menyarankan menggunakan Enum sebagai gantinya:

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

Jika Anda melihat status implementasi fitur bahasa .NET Compiler Platform ("Roslyn"), Anda dapat dengan jelas melihat bahwa di C # 6.0 ini adalah fitur yang direncanakan, jadi pada rilis berikutnya kita dapat melakukannya dengan cara biasa.

Status literal biner

totymedli
sumber
3
Apakah itu terjadi? Tidak semua fitur yang telah di-blog tentang benar-benar membuat rilis Visual Studio 2015.
Kolonel Panic
4
@ColonelPanic - Danation menunjukkan bahwa itu "ada dalam daftar C # 7 sekarang" - 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);

Menggunakan ini, untuk biner 8bit, saya menggunakan ini untuk membuat kelas statis dan memasukkannya ke clipboard .. Kemudian itu akan disisipkan ke proyek dan ditambahkan ke bagian Menggunakan, jadi apa pun dengan nb001010 diambil dari tabel, di paling tidak statis, tapi tetap saja ... Saya menggunakan C # untuk banyak pengkodean gambar PIC dan banyak menggunakan 0b101010 di Hi-Tech C

--contoh dari kode 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
sumber
3

Fitur literal biner tidak diterapkan di C # 6.0 & Visual Studio 2015. tetapi pada 30 Maret 2016 Microsoft mengumumkan versi baru Pratinjau Visual Studio '15' dengan itu kita dapat menggunakan biner literal.

Kita dapat menggunakan satu atau lebih dari satu karakter Garis Bawah (_) untuk pemisah digit. jadi potongan kode akan terlihat seperti:

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

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

dan kita dapat menggunakan 0b dan 0B seperti yang ditunjukkan pada cuplikan kode di atas.

jika Anda tidak ingin menggunakan digit separator Anda dapat menggunakannya tanpa digit separator seperti cuplikan kode di bawah ini

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

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

Meskipun tidak mungkin menggunakan Literal, mungkin BitConverter juga bisa menjadi solusi?

Michael Stum
sumber
BitConverter menjadi sedikit rumit karena merupakan mesin-endian; dan pada Intel standar Anda, itu berarti little-endian. Kebanyakan orang mengalami kesulitan membaca literal little-endian ...
Marc Gravell
1
Aduh, sekarang aku ingat mengapa aku selalu sadar tapi tidak pernah menggunakan BitConverter ...
Michael Stum
4
BitConverter memiliki bidang BitConverter.IsLittleEndian, yang dapat Anda gunakan untuk menguji (dan membalikkan buffer) jika mesin host tidak sedikit endian.
foxy
1

Meskipun solusi penguraian string adalah yang paling populer, saya tidak menyukainya, karena penguraian string dapat menjadi hit kinerja yang hebat dalam beberapa situasi.

Ketika diperlukan semacam bitfield atau topeng biner, saya lebih suka menuliskannya

bitMask panjang = 1011001;

Dan kemudian

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

Atau

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

Di mana kelas BitField berada

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
sumber
4
Yuck. Mengapa tidak menggunakan enum saja? Menggunakan ont ribu berarti 1-0-0-0 hanya meminta masalah.
Clément
1

Anda dapat menggunakan 0b000001sejak Visual Studio 2017 (C # 7.0)

Xiaoyuvax
sumber
0

Pada dasarnya, saya pikir jawabannya TIDAK, tidak ada cara mudah. Gunakan konstanta desimal atau heksadesimal - mereka sederhana dan jelas. Jawaban @RoyTinkers juga bagus - gunakan komentar.

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

Jawaban yang lain di sini menyajikan beberapa pekerjaan yang bermanfaat - tetapi saya pikir mereka tidak lebih baik daripada jawaban sederhana. Desainer bahasa C # mungkin dianggap awalan '0b' tidak perlu. HEX mudah dikonversi ke biner, dan sebagian besar programmer harus mengetahui padanan DEC dari 0-8.

Juga, ketika memeriksa nilai dalam debugger, mereka akan ditampilkan memiliki HEX atau DEC.

RaoulRubin
sumber