Kann ich ein binäres Literal in C oder C ++ verwenden?

190

Ich muss mit einer Binärzahl arbeiten.

Ich habe versucht zu schreiben:

const x = 00010000;

Aber es hat nicht funktioniert.

Ich weiß, dass ich eine Hexadezimalzahl verwenden kann, die denselben Wert hat wie 00010000, aber ich möchte wissen, ob es in C ++ einen Typ für Binärzahlen gibt, und wenn nicht, gibt es eine andere Lösung für mein Problem?

hamza
quelle
51
Sie wissen, dass 00010000das oktal ist, richtig? (Und Ihrer Erklärung fehlt ein Typ.)
Keith Thompson
Hier moderne Art und Weise mit C ++ - Literalen.
Lol4t0
2
C ++ 14 hat hierfür eine Funktion hinzugefügt. Weitere Details finden Sie unten in meiner neuen Antwort. Natürlich benötigt es einen Compiler, der es implementiert.
lpapp
1
@FormlessCloud: Dies sind die Syntaxregeln, die in den C- und C ++ - Standards angegeben sind ( 0berscheint nur in C ++ 14). Sie sind so konzipiert, dass sie eindeutig sind.
Keith Thompson
2
Mögliches Duplikat von Binärliteralen?
MJ Rayburn

Antworten:

70

Sie können verwenden,BOOST_BINARY während Sie auf C ++ 0x warten. :) hat BOOST_BINARYwohl einen Vorteil gegenüber der Template-Implementierung, da es auch in C-Programmen verwendet werden kann (es ist 100% präprozessorgesteuert.)

Um das Gegenteil zu tun (dh eine Zahl in binärer Form auszudrucken), können Sie die nicht portierbare itoaFunktion verwenden oder Ihre eigene implementieren .

Leider können Sie die Basis 2-Formatierung nicht mit STL-Streams durchführen (da setbasenur die Basen 8, 10 und 16 berücksichtigt werden), aber Sie können entweder eine std::stringVersion von itoaoder (die prägnantere, aber geringfügig weniger effiziente) verwenden 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;
}

produziert:

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

Lesen Sie auch Herb Sutters The String Formatters of Manor Farm für eine interessante Diskussion.

vladr
quelle
2
Wie genau die Seite sagt, auf die Sie verlinken, dürfen Sie nur 8, 10 oder 16 mit setbase verwenden. Allerdings:int main() { cout << bitset<8>(42); }
@ Roger danke für den bitsetTipp, ich habe das bisschen schon korrigiert, setbasebevor ich deinen Kommentar gesehen habe.
Vladr
Hier ist ein Tutorial zu benutzerdefinierten Literalen in c ++ 11: akrzemi1.wordpress.com/2012/10/23/user-defined-literals-part-ii . Offensichtlich wird c ++ 1y (auch bekannt als c ++ 14) binäre Literale in den Standard aufnehmen.
Cheshirekow
274

Wenn Sie GCC verwenden, können Sie hierfür eine GCC-Erweiterung (die im C ++ 14-Standard enthalten ist ) verwenden:

int x = 0b00010000;
qrdl
quelle
2
Einige andere Compiler haben diese oder ähnliche Möglichkeiten, Zahlen in Basis 2
auszudrücken
4
Wäre schön, wenn dies standardisiert wäre, aber Clang unterstützt die gleiche Notation.
Polemon
14
Es funktioniert in Clang, GCC und TCC. In PCC funktioniert es nicht. Ich habe keinen anderen Compiler zum Testen.
Michas
6
Ich habe eine Reihe von Compilern für eingebettete Systeme gesehen, die dies unterstützen. Ich kenne keinen bestimmten Grund, warum es keine Standardsprache sein sollte.
Supercat
5
@polemon open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3472.pdf (C ++ 14.)
Jonathan Baldwin
98

Sie können binäre Literale verwenden. Sie sind in C ++ 14 standardisiert. Beispielsweise,

int x = 0b11000;

Unterstützung im GCC

Die Unterstützung in GCC begann in GCC 4.3 (siehe https://gcc.gnu.org/gcc-4.3/changes.html ) als Erweiterung der C-Sprachfamilie (siehe https://gcc.gnu.org/onlinedocs/gcc/). C-Extensions.html # C-Extensions ), aber seit GCC 4.9 wird es jetzt entweder als C ++ 14-Feature oder als Erweiterung erkannt (siehe Unterschied zwischen GCC-Binärliteralen und C ++ 14-Literalen? )

Unterstützung in Visual Studio

Die Unterstützung in Visual Studio wurde in der Visual Studio 2015-Vorschau gestartet (siehe https://www.visualstudio.com/news/vs2015-preview-vs#C++ ).

Mohamed El-Nakib
quelle
5
Sie können 'verwenden, um jedes Teil zu trennen: "0b0000'0100'0100'0001
camino
1
@camino Schön, dass du den ersten verlieren kannst "
Nikos
Dies sollte die akzeptierte Antwort sein. Die meisten anderen Antworten sind sooo veraltet.
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';

Die Ziffer ganz links im Literal muss immer noch 1 sein, aber trotzdem.

wilhelmtell
quelle
4
Bessere Version: bitbucket.org/kniht/scraps/src/tip/cpp/binary.hpp ( binary<10>::value == binary<010>::valueund einige Fehlerprüfungen)
Irgendwie habe ich diese verpasst, bevor ich meine eigene fast identische Antwort gepostet habe. Aber in meiner muss die führende Ziffer 0 sein, nicht 1.
Mark Ransom
4
Eine bessere Version dieser Vorlagenidee: code.google.com/p/cpp-binary-constants
Valentin Galea
@ValentinGalea - warum die Google-Version besser als diese?
AJed
Das ist verdammt beeindruckend. Schade, dass es bei einer hohen Anzahl von Bits nicht funktioniert.
Der Quantenphysiker
31

Einige Compiler (normalerweise die für Mikrocontroller ) verfügen über eine spezielle Funktion, die beim Erkennen von wörtlichen Binärzahlen durch das Präfix "0b ..." vor der Nummer implementiert ist , obwohl die meisten Compiler (C / C ++ - Standards) diese Funktion nicht haben und wenn ja ist der Fall, hier ist es meine alternative Lösung:

#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;

Nachteile (es ist nicht so groß):

  • Die Binärzahlen müssen 4 mal 4 gruppiert werden;
  • Die binären Literale dürfen nur vorzeichenlose Ganzzahlen sein.

Vorteile :

  • Total präprozessorgesteuert, nicht spending processor timein sinnlosen Operationen (like "?.. :..", "<<", "+" ) zum ausführbaren Programm (es kann in der endgültigen Anwendung hundertmal ausgeführt werden);
  • Es funktioniert auch mit "mainly in C"Compilern und C ++ (template+enum solution works only in C++ compilers );
  • Es gibt nur die Einschränkung der "Länge" zum Ausdrücken von "Literalkonstanten" -Werten. Es hätte eine frühzeitige Längenbeschränkung gegeben (normalerweise 8 Bits: 0-255), wenn man konstante Werte durch Parsen der Auflösung von ausgedrückt hätte"enum solution" (usually 255 = reach enum definition limit) "wörtlich konstanten" Beschränkungen der Compiler größere Zahlen zulässt;
  • Einige andere Lösungen erfordern eine übertriebene Anzahl konstanter Definitionen (meiner Meinung nach zu viele Definitionen), einschließlich langer oder several header files(in den meisten Fällen nicht leicht lesbarer und verständlicher), und führen dazu, dass das Projekt unnötig verwirrt und erweitert wird, wie dies bei der Verwendung der Fall ist"BOOST_BINARY()" ).
  • Einfachheit der Lösung: leicht lesbar, verständlich und für andere Fälle einstellbar (könnte auch für die Gruppierung von 8 zu 8 erweitert werden);
Renato Kronleuchter
quelle
Warum wird zB B_0100nicht verwendet (statt 0100)? Wie in z char b = BYTE(0100,0001);.
Peter Mortensen
@PeterMortensen Das B_ wird von der _B2HPräprozessorfunktion hinzugefügt .
mxmlnkn
20

Dieser Thread kann helfen.

/* 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;
}

Es klappt! (Alle Credits gehen an Tom Torfs.)

Federico A. Ramponi
quelle
Ich habe es nicht wirklich verstanden (ich bin ein Anfänger in der Programmierung und speziell in C ++), aber es scheint interessant zu sein, also werde ich versuchen, es nach einigen weiteren C ++ - Studien zu verstehen, danke
hamza
3
Das B8-Makro konvertiert das "binäre" Literal in ein Hex-Literal und extrahiert jedes 4. Bit.
dan04
Ich frage mich, was 0x ## n ## LU bedeutet. Nie auf eine solche Syntax gestoßen.
Federico A. Ramponi
@hamza: es ist in der Tat ziemlich kompliziert. Was Sie jedoch verstehen müssen, ist nur ab #include <stdio>.
Federico A. Ramponi
8
@Federico: Der ##Präprozessor-Operator fügt Token zusammen. Wenn Sie in diesem Fall anrufen HEX__(10), wird es auf erweitert 0x10LU.
James McNellis
18

Wie bereits beantwortet, haben die C-Standards keine Möglichkeit, Binärzahlen direkt zu schreiben. Es gibt jedoch Compiler-Erweiterungen, und anscheinend enthält C ++ 14 das 0bPräfix für Binär. (Beachten Sie, dass diese Antwort ursprünglich im Jahr 2010 veröffentlicht wurde.)

Eine beliebte Problemumgehung besteht darin, eine Header-Datei mit Hilfsmakros einzuschließen . Eine einfache Option besteht auch darin, eine Datei zu generieren, die Makrodefinitionen für alle 8-Bit-Muster enthält, z.

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

Dies führt zu nur 256 #defines, und wenn größere als 8-Bit-Binärkonstanten benötigt werden, können diese Definitionen mit Verschiebungen und ODERs kombiniert werden, möglicherweise mit Hilfsmakros (z.BIN16(B00000001,B00001010) . ). (Einzelne Makros für jeden 16-Bit-, geschweige denn 32-Bit-Wert sind nicht plausibel.)

Der Nachteil ist natürlich, dass für diese Syntax alle führenden Nullen geschrieben werden müssen. Dies kann jedoch auch für Verwendungszwecke wie das Setzen von Bitflags und den Inhalt von Hardwareregistern klarer werden. Ein funktionsähnliches Makro, das zu einer Syntax ohne diese Eigenschaft führt, finden Sie bithacks.hoben verlinkt.

Arkku
quelle
2
Wie groß müsste eine Datei sein, die der CPP lesen müsste, wenn Sie alle Makros für eine hätten long long int?
Wilhelmtell
3
@wilhelmtell: Und welche Relevanz hat das, als ich "alle 8-Bit- Muster" (= 256 Zeilen) spezifizierte und vorschlug, größere Mengen daraus zu kombinieren? Sogar das BOOST_BINARY der akzeptierten Antwort definiert alle 8-Bit-Muster im Header…
Arkku
16

Die C ++ - Über-Engineering-Denkweise ist in den anderen Antworten hier bereits gut berücksichtigt. Hier ist mein Versuch, dies mit einer C-Denkweise zu tun: Keep-it-simple-ffs:

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

C hat keine native Notation für reine Binärzahlen. Ihre beste Wette hier wäre entweder Oktal (zB 07777) oder Hexadezimal (zB 0xfff).

Nikolai Fetissov
quelle
11

Mit der in dieser Frage enthaltenen Funktion können Sie in C ++ bis zu 22 Bit abrufen. Hier ist der Code aus dem Link, entsprechend bearbeitet:

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

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

Sie können also so etwas tun binary<0101011011>::value.

Mark Ransom
quelle
7

Die kleinste Einheit, mit der Sie arbeiten können, ist ein Byte (vom charTyp). Sie können jedoch mit Bits arbeiten, indem Sie bitweise Operatoren verwenden.

Bei ganzzahligen Literalen können Sie nur mit Dezimalzahlen (Basis 10), Oktalzahlen (Basis 8) oder Hexadezimalzahlen (Basis 16) arbeiten. In C und C ++ gibt es keine binären (Basis 2) Literale.

Oktalzahlen wird ein Präfix 0und Hexadezimalzahlen ein Präfix vorangestellt 0x. Dezimalzahlen haben kein Präfix.

In C ++ 0x können Sie übrigens über benutzerdefinierte Literale tun, was Sie wollen .

Brian R. Bondy
quelle
Kann ich zumindest den Binärwert einer Hexadezimalzahl in einer Druck- oder Cout-Funktion anzeigen?
Hamza
Ja, Sie können <shameless_plug> stackoverflow.com/questions/2611764#2611883 </shameless_plug>
vladr
5
Einige C-Compiler unterstützen 0b100101 für binäre Literale, aber es handelt sich leider um eine nicht standardmäßige Erweiterung.
Joey Adams
3
Beachten Sie, dass einige Compiler (insbesondere für Mikrocontroller und eingebettete Systeme) die Syntax für Binärdateien in der Form hinzufügen, obwohl dies nicht im Standard definiert ist 0b00101010. SDCC ist eines davon, und ich bin sicher, dass es auch andere gibt, die dies tun. (Edit: Hah, schlag mich, @Joey!)
Matt B.
5

Sie können die Inline-Baugruppe auch folgendermaßen verwenden:

int i;

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

std::cout << i;

Okay, es könnte etwas übertrieben sein, aber es funktioniert.

renger
quelle
3
Ihre Lösung ist nicht plattformübergreifend. In vielen Architekturen können Sie keinen Assemblycode in C einfügen. Speziell im Microsoft Visual Studio-Compiler können Sie dies (wenn für x86 32-Bit kompiliert). Aber woher wissen Sie überhaupt, ob Ihr Prozessor ein 'eax'-Register hat? Denken Sie an ARM-Prozessoren in Mobiltelefonen, x64-Prozessoren usw. Sie haben kein 'eax'. Der MIPS-Prozessor hat nicht einmal den Befehl 'mov'
DanielHsH
4

Basierend auf einigen anderen Antworten, aber diese wird Programme mit illegalen binären Literalen ablehnen. Führende Nullen sind optional.

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

Beispiel:

#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
quelle
3

Der "Typ" einer Binärzahl ist der gleiche wie jede Dezimal-, Hex- oder Oktalzahl: int(oder sogar char, kurz, lang, lang).

Wenn Sie eine Konstante zuweisen, können Sie sie nicht mit 11011011 zuweisen (seltsamerweise und leider), aber Sie können hex verwenden. Hex ist etwas einfacher mental zu übersetzen. Chunk in Nibbles (4 Bit) und in ein Zeichen in [0-9a-f] übersetzen.

Stephen
quelle
2

Sie können ein Bitset verwenden

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

Ich habe die gute Antwort von @ renato-chandelier erweitert, indem ich die Unterstützung von:

  • _NIBBLE_(…) - 4 Bits, 1 Halbbyte als Argument
  • _BYTE_(…) - 8 Bits, 2 Halbbytes als Argumente
  • _SLAB_(…) - 12 Bit, 3 Halbbytes als Argumente
  • _WORD_(…) - 16 Bit, 4 Halbbytes als Argumente
  • _QUINTIBBLE_(…) - 20 Bits, 5 Knabbereien als Argumente
  • _DSLAB_(…) - 24 Bit, 6 Halbbytes als Argumente
  • _SEPTIBBLE_(…) - 28 Bit, 7 Halbbytes als Argumente
  • _DWORD_(…) - 32 Bit, 8 Halbbytes als Argumente

Bei den Begriffen „Quintibble“ und „Septibble“ bin ich mir eigentlich nicht so sicher. Wenn jemand eine Alternative kennt, lass es mich wissen.

Hier ist das Makro umgeschrieben:

#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))

Und hier ist Renatos Beispiel:

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
quelle
0

Verwenden Sie einfach die Standardbibliothek in C ++:

#include <bitset>

Sie benötigen eine Variable vom Typ std::bitset:

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

In diesem Beispiel habe ich die Binärform von 10in gespeichert x.

8ulDefiniert die Größe Ihrer Bits, 7ulbedeutet also sieben Bits und so weiter.

Hadi Rasekh
quelle
-1

C ++ bietet eine Standardvorlage mit dem Namen std::bitset. Probieren Sie es aus, wenn Sie möchten.

Summer_More_More_Tea
quelle
-9

Sie könnten versuchen, ein Array von bool:

bool i[8] = {0,0,1,1,0,1,0,1}
george wagenknecht
quelle
1
Viele Abstimmungen, keine Erklärung. Hier ist Ihre Erklärung: stackoverflow.com/questions/2064550/c-why-bool-is-8-bits-long Außerdem befindet sich jedes Element in einem Array an einer anderen Speicheradresse. Wir wollen aber eine Folge von gepackten Einsen und Nullen an einer Adresse.
JMI MADISON