Bisakah saya menggunakan literal biner dalam C atau C ++?

191

Saya perlu bekerja dengan nomor biner.

Saya mencoba menulis:

const x = 00010000;

Tapi itu tidak berhasil.

Saya tahu bahwa saya dapat menggunakan angka heksadesimal yang memiliki nilai yang sama 00010000, tetapi saya ingin tahu apakah ada tipe dalam C ++ untuk angka-angka biner dan jika tidak, apakah ada solusi lain untuk masalah saya?

hamza
sumber
51
Anda tahu itu 00010000oktal, bukan? (Dan deklarasi Anda tidak memiliki tipe.)
Keith Thompson
Di sini cara modern menggunakan C ++ literals.
Lol4t0
2
C ++ 14 menambahkan fitur untuk ini. Lihat jawaban baru saya untuk detail lebih lanjut di bagian bawah. Tentu saja, itu membutuhkan kompiler yang mengimplementasikannya.
lpapp
1
@FormlessCloud: Ini adalah aturan sintaks yang diberikan dalam standar C dan C ++ ( 0bhanya muncul di C ++ 14). Mereka dirancang untuk tidak ambigu.
Keith Thompson
2
Kemungkinan duplikat dari Binary literals?
MJ Rayburn

Jawaban:

70

Anda dapat menggunakanBOOST_BINARY sambil menunggu C ++ 0x. :) BOOST_BINARYbisa dibilang memiliki keunggulan dibandingkan implementasi templat sejauh dapat digunakan dalam program C juga (100% preprocessor-driven.)

Untuk melakukan sebaliknya (yaitu mencetak angka dalam bentuk biner), Anda dapat menggunakan non-portabel itoafungsi , atau menerapkan sendiri .

Sayangnya Anda tidak dapat melakukan pemformatan basis 2 dengan aliran STL (karena setbasehanya akan menghormati basis 8, 10 dan 16), tetapi Anda dapat menggunakan std::stringversi itoa, atau (yang lebih ringkas, namun sedikit kurang efisien) std::bitset.

#include <boost/utility/binary.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <bitset>
#include <iostream>
#include <iomanip>

using namespace std;

int main() {
  unsigned short b = BOOST_BINARY( 10010 );
  char buf[sizeof(b)*8+1];
  printf("hex: %04x, dec: %u, oct: %06o, bin: %16s\n", b, b, b, itoa(b, buf, 2));
  cout << setfill('0') <<
    "hex: " << hex << setw(4) << b << ", " <<
    "dec: " << dec << b << ", " <<
    "oct: " << oct << setw(6) << b << ", " <<
    "bin: " << bitset< 16 >(b) << endl;
  return 0;
}

menghasilkan:

hex: 0012, dec: 18, oct: 000022, bin:            10010
hex: 0012, dec: 18, oct: 000022, bin: 0000000000010010

Baca juga buku The String Formatters dari Manor Farm milik Herb Sutter untuk diskusi yang menarik.

vladr
sumber
2
Seperti halaman yang Anda tautkan mengatakan, Anda hanya dapat menggunakan 8, 10, atau 16 dengan setbase. Namun:int main() { cout << bitset<8>(42); }
@Roger terima kasih atas bitsettipnya, saya sudah sedikit mengoreksi setbasesebelum saya melihat komentar Anda.
vladr
Berikut tutorial tentang literal yang ditentukan pengguna di c ++ 11: akrzemi1.wordpress.com/2012/10/23/user-defined-literals-part-ii . Jelas c ++ 1y (alias c ++ 14) akan menyertakan literal biner dalam standar.
cheshirekow
275

Jika Anda menggunakan GCC maka Anda dapat menggunakan ekstensi GCC (yang termasuk dalam standar C ++ 14 ) untuk ini:

int x = 0b00010000;
qrdl
sumber
2
Beberapa kompiler lain memiliki ini atau cara lain yang serupa untuk mengekspresikan angka dalam basis 2.
nategoose
4
Akan menyenangkan untuk memiliki standar ini, tetapi dentang mendukung notasi yang sama.
polemon
14
Ini bekerja di Dentang, GCC, dan TCC. Itu tidak bekerja di PCC. Saya tidak punya kompiler lain untuk diuji.
Michas
6
Saya telah melihat sejumlah kompiler sistem embedded yang mendukungnya. Saya tidak tahu alasan tertentu mengapa itu tidak menjadi fitur bahasa standar.
supercat
5
@polemon open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3472.pdf (C ++ 14.)
Jonathan Baldwin
98

Anda dapat menggunakan literal biner. Mereka distandarisasi dalam C ++ 14. Sebagai contoh,

int x = 0b11000;

Dukungan dalam GCC

Dukungan dalam GCC dimulai pada GCC 4.3 (lihat https://gcc.gnu.org/gcc-4.3/changes.html ) sebagai ekstensi ke keluarga bahasa C (lihat https://gcc.gnu.org/onlinedocs/gcc/ C-Extensions.html # C-Extensions ), tetapi karena GCC 4.9 sekarang dikenal sebagai fitur C ++ 14 atau ekstensi (lihat Perbedaan antara literal biner GCC dan yang C ++ 14? )

Dukungan dalam Visual Studio

Dukungan di Visual Studio dimulai di Visual Studio 2015 Preview (lihat https://www.visualstudio.com/news/vs2015-preview-vs#C++ ).

Mohamed El-Nakib
sumber
5
Anda dapat menggunakan 'untuk memisahkan setiap bagian: "0b0000'0100'0100'0001
camino
1
@camino Bagus Anda bisa kehilangan yang pertama "
Nikos
Ini harus menjadi jawaban yang diterima. Sebagian besar jawaban lainnya sudah ketinggalan jaman.
Alex
73
template<unsigned long N>
struct bin {
    enum { value = (N%10)+2*bin<N/10>::value };
} ;

template<>
struct bin<0> {
    enum { value = 0 };
} ;

// ...
    std::cout << bin<1000>::value << '\n';

Digit paling kiri dari literal masih harus 1, tetapi tetap saja.

wilhelmtell
sumber
4
Versi yang lebih baik: bitbucket.org/kniht/scraps/src/tip/cpp/binary.hpp ( binary<10>::value == binary<010>::valuedan beberapa pengecekan error)
Entah bagaimana melewatkan yang ini sebelum saya memposting jawaban saya yang hampir identik. Tetapi di tambang saya digit pertama harus 0, bukan 1.
Mark Ransom
4
Versi yang lebih baik dari gagasan templat ini: code.google.com/p/cpp-binary-constants
Valentin Galea
@ValentinGalea - mengapa versi google lebih baik dari ini?
AJed
Ini sangat mengesankan. Sayang sekali itu tidak bekerja untuk jumlah bit yang tinggi.
Fisikawan Kuantum
31

Beberapa kompiler (biasanya yang untuk mikrokontroler ) memiliki fitur khusus yang diimplementasikan dalam mengenali angka biner literal dengan awalan "0b ..." sebelum nomor tersebut, meskipun sebagian besar kompiler (standar C / C ++) tidak memiliki fitur seperti itu dan jika itu ini masalahnya, ini dia solusi alternatif saya:

#define B_0000    0
#define B_0001    1
#define B_0010    2
#define B_0011    3
#define B_0100    4
#define B_0101    5
#define B_0110    6
#define B_0111    7
#define B_1000    8
#define B_1001    9
#define B_1010    a
#define B_1011    b
#define B_1100    c
#define B_1101    d
#define B_1110    e
#define B_1111    f

#define _B2H(bits)    B_##bits
#define B2H(bits)    _B2H(bits)
#define _HEX(n)        0x##n
#define HEX(n)        _HEX(n)
#define _CCAT(a,b)    a##b
#define CCAT(a,b)   _CCAT(a,b)

#define BYTE(a,b)        HEX( CCAT(B2H(a),B2H(b)) )
#define WORD(a,b,c,d)    HEX( CCAT(CCAT(B2H(a),B2H(b)),CCAT(B2H(c),B2H(d))) )
#define DWORD(a,b,c,d,e,f,g,h)    HEX( CCAT(CCAT(CCAT(B2H(a),B2H(b)),CCAT(B2H(c),B2H(d))),CCAT(CCAT(B2H(e),B2H(f)),CCAT(B2H(g),B2H(h)))) )

// Using example
char b = BYTE(0100,0001); // Equivalent to b = 65; or b = 'A'; or b = 0x41;
unsigned int w = WORD(1101,1111,0100,0011); // Equivalent to w = 57155; or w = 0xdf43;
unsigned long int dw = DWORD(1101,1111,0100,0011,1111,1101,0010,1000); //Equivalent to dw = 3745774888; or dw = 0xdf43fd28;

Kerugian (bukan yang besar):

  • Angka-angka biner harus dikelompokkan 4 oleh 4;
  • Literal biner harus berupa bilangan bulat tak bertanda;

Keuntungan :

  • Total preprocessor didorong, bukan spending processor timedalam operasi pointless ( like "?.. :..", "<<", "+") ke program yang dapat dieksekusi (dapat dilakukan ratusan kali dalam aplikasi akhir);
  • Ia bekerja dengan "mainly in C"kompiler dan C ++ juga ( template+enum solution works only in C++ compilers);
  • Ia hanya memiliki batasan "panjang" untuk mengekspresikan nilai "konstanta literal". Akan ada batasan longness awal (biasanya 8 bit: 0-255) jika seseorang telah menyatakan nilai konstan dengan mengurai tekad "enum solution" (usually 255 = reach enum definition limit), berbeda, batasan "literal konstan", dalam kompiler memungkinkan jumlah yang lebih besar;
  • Beberapa solusi lain menuntut jumlah definisi konstan yang berlebihan (terlalu banyak mendefinisikan menurut saya) termasuk panjang atau several header files(dalam banyak kasus tidak mudah dibaca dan dimengerti, dan membuat proyek menjadi tidak perlu membingungkan dan diperluas, seperti menggunakan "BOOST_BINARY()");
  • Kesederhanaan solusinya: mudah dibaca, dimengerti dan dapat disesuaikan untuk kasus-kasus lain (juga dapat diperluas untuk pengelompokan 8 oleh 8);
Lampu Renato
sumber
Mengapa misalnya B_0100tidak digunakan (bukan 0100)? Seperti pada misalnya char b = BYTE(0100,0001);.
Peter Mortensen
@PeterMortensen B_ akan ditambahkan oleh _B2Hfungsi preprocessor.
mxmlnkn
20

Utas ini dapat membantu.

/* Helper macros */
#define HEX__(n) 0x##n##LU
#define B8__(x) ((x&0x0000000FLU)?1:0) \
+((x&0x000000F0LU)?2:0) \
+((x&0x00000F00LU)?4:0) \
+((x&0x0000F000LU)?8:0) \
+((x&0x000F0000LU)?16:0) \
+((x&0x00F00000LU)?32:0) \
+((x&0x0F000000LU)?64:0) \
+((x&0xF0000000LU)?128:0)

/* User macros */
#define B8(d) ((unsigned char)B8__(HEX__(d)))
#define B16(dmsb,dlsb) (((unsigned short)B8(dmsb)<<8) \
+ B8(dlsb))
#define B32(dmsb,db2,db3,dlsb) (((unsigned long)B8(dmsb)<<24) \
+ ((unsigned long)B8(db2)<<16) \
+ ((unsigned long)B8(db3)<<8) \
+ B8(dlsb))


#include <stdio.h>

int main(void)
{
    // 261, evaluated at compile-time
    unsigned const number = B16(00000001,00000101);

    printf("%d \n", number);
    return 0;
}

Berhasil! (Semua kredit jatuh ke Tom Torfs.)

Federico A. Ramponi
sumber
saya tidak benar-benar mengerti (ima pemula dalam pemrograman & khususnya dalam C ++) tetapi tampaknya menarik jadi saya akan mencoba untuk memahaminya setelah beberapa studi C ++ lagi, terima kasih
hamza
3
Makro B8 bekerja dengan mengubah literal "biner" menjadi hex literal dan mengekstraksi setiap bit ke-4.
dan04
Saya ingin tahu apa arti 0x ## n ## LU? Tidak pernah menjumpai sintaksis seperti itu.
Federico A. Ramponi
@hamza: ini memang agak rumit. Tapi yang perlu Anda pahami hanyalah dari #include <stdio> dan seterusnya.
Federico A. Ramponi
8
@Federico: ##Operator preprocessor menempelkan token bersama. Jadi, dalam hal ini, jika Anda menelepon HEX__(10), itu akan diperluas ke 0x10LU.
James McNellis
18

Seperti yang sudah dijawab, standar C tidak memiliki cara untuk secara langsung menulis angka biner. Namun, ada ekstensi kompiler, dan tampaknya C ++ 14 menyertakan 0bawalan untuk biner. (Perhatikan bahwa jawaban ini awalnya diposting pada tahun 2010.)

Salah satu solusi yang populer adalah memasukkan file header dengan makro pembantu . Salah satu opsi yang mudah adalah menghasilkan file yang menyertakan definisi makro untuk semua pola 8-bit, misalnya:

#define B00000000 0
#define B00000001 1
#define B00000010 2

Ini menghasilkan hanya 256 #definedetik, dan jika lebih besar dari konstanta biner 8-bit diperlukan, definisi ini dapat dikombinasikan dengan shift dan OR, mungkin dengan macro pembantu (misalnya, BIN16(B00000001,B00001010)). (Memiliki makro individu untuk setiap 16-bit, apalagi 32-bit, nilainya tidak masuk akal.)

Tentu saja downside adalah bahwa sintaks ini mengharuskan penulisan semua nol terkemuka, tetapi ini juga dapat membuatnya lebih jelas untuk penggunaan seperti pengaturan bendera bit dan isi register perangkat keras. Untuk makro seperti fungsi yang menghasilkan sintaksis tanpa properti ini, lihat bithacks.htertaut di atas.

Arkku
sumber
2
Jadi, seberapa besar file yang perlu dibaca CPP jika Anda memiliki semua makro untuk long long int?
wilhelmtell
3
@wilhelmtell: Dan apa relevansinya ketika saya menentukan “semua pola 8-bit ” (= 256 garis), dan menyarankan menggabungkan jumlah yang lebih besar dari itu? Bahkan BOOST_BINARY dari jawaban yang diterima mendefinisikan semua pola 8-bit di header ...
Arkku
16

Pola pikir over-engineering C ++ sudah diperhitungkan dengan baik dalam jawaban lain di sini. Inilah upaya saya melakukannya dengan pola pikir C, keep-it-simple-ffs:

unsigned char x = 0xF; // binary: 00001111
Craig
sumber
12

C tidak memiliki notasi asli untuk angka biner murni. Taruhan terbaik Anda di sini adalah oktal (misal 07777) dari heksadesimal (mis 0xfff).

Nikolai Fetissov
sumber
11

Anda dapat menggunakan fungsi yang ditemukan dalam pertanyaan ini untuk mendapatkan hingga 22 bit dalam C ++. Berikut kode dari tautan, yang diedit sesuai:

template< unsigned long long N >
struct binary
{
  enum { value = (N % 8) + 2 * binary< N / 8 > :: value } ;
};

template<>
struct binary< 0 >
{
  enum { value = 0 } ;
};

Jadi Anda bisa melakukan sesuatu seperti binary<0101011011>::value.

Mark tebusan
sumber
7

Unit terkecil yang dapat Anda gunakan adalah byte (yang charbertipe). Anda dapat bekerja dengan bit meskipun dengan menggunakan operator bitwise.

Sedangkan untuk bilangan bulat integer, Anda hanya dapat bekerja dengan angka desimal (basis 10), oktal (basis 8) atau heksadesimal (basis 16). Tidak ada literal biner (basis 2) dalam C atau C ++.

Angka oktal diawali dengan 0dan angka heksadesimal diawali dengan 0x. Angka desimal tidak memiliki awalan.

Dalam C ++ 0x Anda akan dapat melakukan apa yang Anda inginkan dengan cara melalui literal yang ditentukan pengguna .

Brian R. Bondy
sumber
bisakah saya setidaknya menunjukkan nilai Biner dari heksadesimal dalam fungsi cetak atau fungsi cout?
hamza
Ya, Anda dapat <shameless_plug> stackoverflow.com/questions/2611764#2611883 </shameless_plug>
vladr
5
Beberapa kompiler C mendukung 0b100101 untuk literal biner, tetapi sayangnya ini merupakan ekstensi yang tidak standar.
Joey Adams
3
Perhatikan bahwa, meskipun tidak didefinisikan dalam standar, beberapa kompiler (terutama untuk mikrokontroler dan sistem tertanam) menambahkan sintaks untuk biner dalam bentuk 0b00101010sebagai kenyamanan. SDCC adalah satu, dan saya yakin ada yang lain juga. (Sunting: Hah, pukuli aku untuk itu, @ Joey!)
Matt B.
5

Anda juga dapat menggunakan rakitan inline seperti ini:

int i;

__asm {
    mov eax, 00000000000000000000000000000000b
    mov i,   eax
}

std::cout << i;

Oke, ini mungkin agak berlebihan, tetapi berhasil.

pembalap
sumber
3
Solusi Anda bukan multi-platform. Dalam banyak arsitektur Anda tidak dapat memasukkan kode assembly dalam C. Khususnya di kompiler Microsoft Visual studio Anda dapat (ketika dikompilasi untuk x86 32bits). Tetapi bagaimana Anda bahkan tahu jika prosesor Anda memiliki register 'eax'? Pikirkan prosesor ARM di ponsel, prosesor x64, dll. Mereka tidak memiliki 'eax'. Prosesor MIPS bahkan tidak memiliki perintah 'mov'
DanielHsH
4

Berdasarkan beberapa jawaban lain, tetapi yang ini akan menolak program dengan literal biner ilegal. Nol terkemuka adalah opsional.

template<bool> struct BinaryLiteralDigit;

template<> struct BinaryLiteralDigit<true> {
    static bool const value = true;
};

template<unsigned long long int OCT, unsigned long long int HEX>
struct BinaryLiteral {
    enum {
        value = (BinaryLiteralDigit<(OCT%8 < 2)>::value && BinaryLiteralDigit<(HEX >= 0)>::value
            ? (OCT%8) + (BinaryLiteral<OCT/8, 0>::value << 1)
            : -1)
    };
};

template<>
struct BinaryLiteral<0, 0> {
    enum {
        value = 0
    };
};

#define BINARY_LITERAL(n) BinaryLiteral<0##n##LU, 0x##n##LU>::value

Contoh:

#define B BINARY_LITERAL

#define COMPILE_ERRORS 0

int main (int argc, char ** argv) {
    int _0s[] = { 0, B(0), B(00), B(000) };
    int _1s[] = { 1, B(1), B(01), B(001) };
    int _2s[] = { 2, B(10), B(010), B(0010) };
    int _3s[] = { 3, B(11), B(011), B(0011) };
    int _4s[] = { 4, B(100), B(0100), B(00100) };

    int neg8s[] = { -8, -B(1000) };

#if COMPILE_ERRORS
    int errors[] = { B(-1), B(2), B(9), B(1234567) };
#endif

    return 0;
}
Thomas Eding
sumber
3

"Jenis" angka biner sama dengan angka desimal, hex atau oktal: int(atau bahkan char, pendek, panjang).

Saat Anda menetapkan konstanta, Anda tidak bisa menetapkannya dengan 11011011 (dengan rasa ingin tahu dan sayangnya), tetapi Anda bisa menggunakan hex. Hex sedikit lebih mudah untuk diterjemahkan secara mental. Potong nibble (4 bit) dan terjemahkan ke karakter dalam [0-9a-f].

Stephen
sumber
2

Anda bisa menggunakan bitset

bitset<8> b(string("00010000"));
int i = (int)(bs.to_ulong());
cout<<i;
Deqing
sumber
2

Saya memberikan jawaban yang bagus yang diberikan oleh @ renato-chandelier dengan memastikan dukungan dari:

  • _NIBBLE_(…) - 4 bit, 1 gigit sebagai argumen
  • _BYTE_(…) - 8 bit, 2 camilan sebagai argumen
  • _SLAB_(…) - 12 bit, 3 camilan sebagai argumen
  • _WORD_(…) - 16 bit, 4 camilan sebagai argumen
  • _QUINTIBBLE_(…) - 20 bit, 5 camilan sebagai argumen
  • _DSLAB_(…) - 24 bit, 6 camilan sebagai argumen
  • _SEPTIBBLE_(…) - 28 bit, 7 camilan sebagai argumen
  • _DWORD_(…) - 32 bit, 8 camilan sebagai argumen

Saya sebenarnya tidak begitu yakin tentang istilah "quintibble" dan "septibble". Jika ada yang tahu alternatifnya, beri tahu saya.

Inilah makro yang ditulis ulang:

#define __CAT__(A, B) A##B
#define _CAT_(A, B) __CAT__(A, B)

#define __HEX_0000 0
#define __HEX_0001 1
#define __HEX_0010 2
#define __HEX_0011 3
#define __HEX_0100 4
#define __HEX_0101 5
#define __HEX_0110 6
#define __HEX_0111 7
#define __HEX_1000 8
#define __HEX_1001 9
#define __HEX_1010 a
#define __HEX_1011 b
#define __HEX_1100 c
#define __HEX_1101 d
#define __HEX_1110 e
#define __HEX_1111 f

#define _NIBBLE_(N1) _CAT_(0x, _CAT_(__HEX_, N1))
#define _BYTE_(N1, N2) _CAT_(_NIBBLE_(N1), _CAT_(__HEX_, N2))
#define _SLAB_(N1, N2, N3) _CAT_(_BYTE_(N1, N2), _CAT_(__HEX_, N3))
#define _WORD_(N1, N2, N3, N4) _CAT_(_SLAB_(N1, N2, N3), _CAT_(__HEX_, N4))
#define _QUINTIBBLE_(N1, N2, N3, N4, N5) _CAT_(_WORD_(N1, N2, N3, N4), _CAT_(__HEX_, N5))
#define _DSLAB_(N1, N2, N3, N4, N5, N6) _CAT_(_QUINTIBBLE_(N1, N2, N3, N4, N5), _CAT_(__HEX_, N6))
#define _SEPTIBBLE_(N1, N2, N3, N4, N5, N6, N7) _CAT_(_DSLAB_(N1, N2, N3, N4, N5, N6), _CAT_(__HEX_, N7))
#define _DWORD_(N1, N2, N3, N4, N5, N6, N7, N8) _CAT_(_SEPTIBBLE_(N1, N2, N3, N4, N5, N6, N7), _CAT_(__HEX_, N8))

Dan inilah contoh penggunaan Renato:

char b = _BYTE_(0100, 0001); /* equivalent to b = 65; or b = 'A'; or b = 0x41; */
unsigned int w = _WORD_(1101, 1111, 0100, 0011); /* equivalent to w = 57155; or w = 0xdf43; */
unsigned long int dw = _DWORD_(1101, 1111, 0100, 0011, 1111, 1101, 0010, 1000); /* Equivalent to dw = 3745774888; or dw = 0xdf43fd28; */
madmurphy
sumber
0

Cukup gunakan perpustakaan standar di C ++:

#include <bitset>

Anda memerlukan variabel tipe std::bitset:

std::bitset<8ul> x;
x = std::bitset<8>(10);
for (int i = x.size() - 1; i >= 0; i--) {
      std::cout << x[i];
}

Dalam contoh ini, saya menyimpan bentuk biner 10di x.

8ulmendefinisikan ukuran bit Anda, jadi 7ulartinya tujuh bit dan sebagainya.

Hadi Rasekh
sumber
-1

C ++ menyediakan templat standar bernama std::bitset. Cobalah jika Anda suka.

Summer_More_More_Tea
sumber
-9

Anda dapat mencoba menggunakan larik bool:

bool i[8] = {0,0,1,1,0,1,0,1}
george wagenknecht
sumber
2
Banyak downvotes, tidak ada penjelasan. Inilah penjelasan Anda: stackoverflow.com/questions/2064550/c-why-bool-is-8-bits-long Juga, setiap elemen dalam array berada pada alamat memori yang berbeda. Tapi kami ingin urutan 1 dan 0 yang dikemas di satu alamat.
JMI MADISON