Puis-je utiliser un littéral binaire en C ou C ++?

191

J'ai besoin de travailler avec un nombre binaire.

J'ai essayé d'écrire:

const x = 00010000;

Mais ça n'a pas marché.

Je sais que je peux utiliser un nombre hexadécimal qui a la même valeur que 00010000, mais je veux savoir s'il existe un type en C ++ pour les nombres binaires et s'il n'y en a pas, y a-t-il une autre solution à mon problème?

Hamza
la source
51
Vous savez que 00010000c'est octal, non? (Et il manque un type dans votre déclaration.)
Keith Thompson
Voici une manière moderne d'utiliser les littéraux C ++.
Lol4t0
2
C ++ 14 a ajouté une fonctionnalité pour cela. Voir ma nouvelle réponse pour plus de détails en bas. Bien sûr, il nécessite un compilateur qui l'implémente.
lpapp
1
@FormlessCloud: Ce sont les règles de syntaxe données dans les standards C et C ++ ( 0bn'apparaissent que dans C ++ 14). Ils sont conçus pour être sans ambiguïté.
Keith Thompson
2
Possible duplication de littéraux binaires?
MJ Rayburn

Réponses:

70

Vous pouvez utiliserBOOST_BINARY en attendant C ++ 0x. :) a BOOST_BINARYsans doute un avantage sur l'implémentation de modèle dans la mesure où il peut également être utilisé dans les programmes C (il est 100% piloté par un préprocesseur).

Pour ce faire l'inverse (c. -à imprimer un nombre sous forme binaire), vous pouvez utiliser la non-portable itoafonction ou mettre en œuvre votre propre .

Malheureusement, vous ne pouvez pas faire de formatage de base 2 avec des flux STL (puisque setbasene respectera que les bases 8, 10 et 16), mais vous pouvez utiliser une std::stringversion de itoa, ou (la plus concise, mais légèrement moins efficace) 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;
}

produit:

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

Lisez également The String Formatters of Manor Farm de Herb Sutter pour une discussion intéressante.

vladr
la source
2
Comme l'indique la page même vers laquelle vous créez un lien, vous ne pouvez utiliser que 8, 10 ou 16 avec setbase. Cependant:int main() { cout << bitset<8>(42); }
@Roger merci pour le bitsettuyau, j'ai déjà corrigé le problème setbaseavant de voir votre commentaire.
vladr
Voici un didacticiel sur les littéraux définis par l'utilisateur en c ++ 11: akrzemi1.wordpress.com/2012/10/23/user-defined-literals-part-ii . Évidemment, c ++ 1y (alias c ++ 14) inclura des littéraux binaires dans le standard.
cheshirekow le
275

Si vous utilisez GCC, vous pouvez utiliser une extension GCC (qui est incluse dans la norme C ++ 14 ) pour cela:

int x = 0b00010000;
qrdl
la source
2
Plusieurs autres compilateurs ont ceci ou d'autres moyens similaires d'exprimer des nombres en base 2.
nategoose
4
Ce serait bien d'avoir ce standardisé, mais clang prend en charge la même notation.
polemon
14
Cela fonctionne dans Clang, GCC et TCC. Cela ne fonctionne pas dans PCC. Je n'ai pas d'autre compilateur pour tester.
Michas
6
J'ai vu un certain nombre de compilateurs de systèmes embarqués qui le prennent en charge. Je ne connais aucune raison particulière pour laquelle cela ne devrait pas être une fonctionnalité de langage standard.
supercat
5
@polemon open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3472.pdf (C ++ 14.)
Jonathan Baldwin
98

Vous pouvez utiliser des littéraux binaires. Ils sont standardisés en C ++ 14. Par exemple,

int x = 0b11000;

Assistance dans GCC

La prise en charge de GCC a commencé dans GCC 4.3 (voir https://gcc.gnu.org/gcc-4.3/changes.html ) en tant qu'extensions de la famille de langages C (voir https://gcc.gnu.org/onlinedocs/gcc/ C-Extensions.html # C-Extensions ), mais depuis GCC 4.9, il est maintenant reconnu comme une fonctionnalité C ++ 14 ou une extension (voir Différence entre les littéraux binaires GCC et ceux C ++ 14? )

Prise en charge dans Visual Studio

La prise en charge dans Visual Studio a démarré dans Visual Studio 2015 Preview (voir https://www.visualstudio.com/news/vs2015-preview-vs#C++ ).

Mohamed El-Nakib
la source
5
Vous pouvez utiliser 'pour séparer chaque partie: "0b0000'0100'0100'0001
camino
1
@camino Nice, vous pouvez perdre le premier "
Nikos
Cela devrait être la réponse acceptée. La plupart des autres réponses sont tellement dépassées.
Alex le
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';

Le chiffre le plus à gauche du littéral doit toujours être 1, mais néanmoins.

Wilhelmtell
la source
4
Meilleure version: bitbucket.org/kniht/scraps/src/tip/cpp/binary.hpp ( binary<10>::value == binary<010>::valueet quelques vérifications d'erreurs)
J'ai manqué celui-ci avant de publier ma propre réponse presque identique. Mais dans le mien, le premier chiffre doit être 0, pas 1.
Mark Ransom
4
Une meilleure version de cette idée de modèle: code.google.com/p/cpp-binary-constants
Valentin Galea
@ValentinGalea - pourquoi la version Google est-elle meilleure que celle-ci?
AJed
C'est vraiment impressionnant. Dommage que cela ne fonctionne pas pour un nombre élevé de bits.
The Quantum Physicist
31

Quelques compilateurs (généralement ceux des microcontrôleurs ) ont une fonction spéciale implémentée dans la reconnaissance des nombres binaires littéraux par le préfixe "0b ..." précédant le nombre, bien que la plupart des compilateurs (normes C / C ++) ne disposent pas d'une telle fonctionnalité et si elle c'est le cas, voici ma solution alternative:

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

Inconvénients (ce n'est pas si gros):

  • Les nombres binaires doivent être groupés 4 par 4;
  • Les littéraux binaires doivent être uniquement des nombres entiers non signés;

Avantages :

  • Totalement piloté par le préprocesseur, pas spending processor timeen opérations inutiles ( like "?.. :..", "<<", "+") vers le programme exécutable (il peut être effectué des centaines de fois dans l'application finale);
  • Il fonctionne également avec les "mainly in C"compilateurs et C ++ ( template+enum solution works only in C++ compilers);
  • Il n'a que la limitation de la «longévité» pour exprimer des valeurs «constantes littérales». Il y aurait eu une limitation de longueur précoce (généralement 8 bits: 0-255) si l'on avait exprimé des valeurs constantes en analysant la résolution "enum solution" (usually 255 = reach enum definition limit), différemment, des limitations de "constante littérale", dans le compilateur autorise des nombres plus grands;
  • Certaines autres solutions exigent un nombre exagéré de définitions constantes (trop de définitions à mon avis), y compris longues ou several header files(dans la plupart des cas, pas facilement lisibles et compréhensibles, et rendent le projet inutilement confus et étendu, comme cela en utilisant"BOOST_BINARY()" );
  • Simplicité de la solution: facilement lisible, compréhensible et ajustable pour d'autres cas (pourrait être étendue pour le groupement 8 par 8 aussi);
Lustre Renato
la source
Pourquoi, par exemple, B_0100n'est-il pas utilisé (au lieu de 0100)? Comme par exemple char b = BYTE(0100,0001);.
Peter Mortensen
@PeterMortensen Le B_ est ajouté par la _B2Hfonction de préprocesseur.
mxmlnkn
20

Ce fil peut aider.

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

Ça marche! (Tous les crédits vont à Tom Torfs.)

Federico A. Ramponi
la source
je n'ai pas vraiment compris (je suis débutant en programmation et spécialement en C ++) mais cela semble intéressant donc je vais essayer de le comprendre après quelques études supplémentaires en C ++, merci
hamza
3
La macro B8 fonctionne en convertissant le littéral «binaire» en littéral hexadécimal et en extrayant tous les 4 bits.
dan04
Je me demande ce que signifie 0x ## n ## LU? Jamais rencontré une telle syntaxe.
Federico A. Ramponi
@hamza: c'est en effet assez complexe. Mais ce que vous devez comprendre, c'est juste à partir de #include <stdio>.
Federico A. Ramponi
8
@Federico: l' ##opérateur du préprocesseur colle les jetons ensemble. Donc, dans ce cas, si vous appelez HEX__(10), il se développe en 0x10LU.
James McNellis
18

Comme déjà répondu, les standards C n'ont aucun moyen d'écrire directement des nombres binaires. Il existe cependant des extensions de compilateur et apparemment C ++ 14 inclut le 0bpréfixe pour binary. (Notez que cette réponse a été publiée à l'origine en 2010.)

Une solution de contournement populaire consiste à inclure un fichier d'en-tête avec des macros d'assistance . Une option simple consiste également à générer un fichier qui comprend des définitions de macros pour tous les modèles 8 bits, par exemple:

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

Cela ne donne que 256 #defines, et si des constantes binaires supérieures à 8 bits sont nécessaires, ces définitions peuvent être combinées avec des décalages et des OR, éventuellement avec des macros d'assistance (par exemple,BIN16(B00000001,B00001010) ). (Avoir des macros individuelles pour chaque valeur de 16 bits, sans parler de 32 bits, n'est pas plausible.)

Bien sûr, l'inconvénient est que cette syntaxe nécessite l'écriture de tous les zéros non significatifs, mais cela peut également le rendre plus clair pour des utilisations telles que la définition d'indicateurs de bits et le contenu des registres matériels. Pour une macro de type fonction résultant en une syntaxe sans cette propriété, voir bithacks.hlien ci-dessus.

Arkku
la source
2
Alors, quelle taille de fichier le CPP aurait-il besoin de lire si vous aviez toutes les macros pour un long long int?
wilhelmtell
3
@wilhelmtell: Et quelle est la pertinence de cela quand j'ai spécifié «tous les modèles 8 bits » (= 256 lignes), et suggéré de combiner de plus grandes quantités de ceux-ci? Même le BOOST_BINARY de la réponse acceptée définit tous les modèles 8 bits dans l'en-tête…
Arkku
16

L'état d'esprit de sur-ingénierie C ++ est déjà bien pris en compte dans les autres réponses ici. Voici ma tentative de le faire avec un état d'esprit C, keep-it-simple-ffs:

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

C n'a pas de notation native pour les nombres binaires purs. Votre meilleur pari ici serait octal (par exemple 07777) ou hexadécimal (par exemple 0xfff).

Nikolai Fetissov
la source
11

Vous pouvez utiliser la fonction trouvée dans cette question pour obtenir jusqu'à 22 bits en C ++. Voici le code du lien, correctement édité:

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

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

Vous pouvez donc faire quelque chose comme binary<0101011011>::value.

Mark Ransom
la source
7

La plus petite unité avec laquelle vous pouvez travailler est un octet (qui est de chartype). Vous pouvez cependant travailler avec des bits en utilisant des opérateurs au niveau du bit.

Comme pour les littéraux entiers, vous ne pouvez travailler qu'avec des nombres décimaux (base 10), octaux (base 8) ou hexadécimaux (base 16). Il n'y a pas de littéraux binaires (base 2) en C ni en C ++.

Les nombres octaux sont préfixés par 0et les nombres hexadécimaux sont préfixés par 0x. Les nombres décimaux n'ont pas de préfixe.

En C ++ 0x, vous pourrez faire ce que vous voulez en passant via des littéraux définis par l' utilisateur .

Brian R. Bondy
la source
puis-je au moins afficher la valeur binaire d'un hexadécimal dans une fonction d'impression ou de cout?
hamza
Oui, vous pouvez <shameless_plug> stackoverflow.com/questions/2611764#2611883 </shameless_plug>
vladr
5
Certains compilateurs C prennent en charge 0b100101 pour les littéraux binaires, mais ce n'est malheureusement pas une extension standard.
Joey Adams
3
Notez que, bien que ce ne soit pas défini dans la norme, certains compilateurs (notamment ceux pour les microcontrôleurs et les systèmes embarqués) ajoutent la syntaxe pour binaire dans le formulaire 0b00101010pour plus de commodité. Le SDCC en est un, et je suis sûr qu'il y en a d'autres qui le font aussi. (Edit: Hah, bat-moi dessus, @Joey!)
Matt B.
5

Vous pouvez également utiliser l'assemblage en ligne comme ceci:

int i;

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

std::cout << i;

D'accord, c'est peut-être un peu exagéré, mais cela fonctionne.

renger
la source
3
Votre solution n'est pas multi-plateforme. Dans de nombreuses architectures, vous ne pouvez pas inclure de code d'assembly dans C. Plus précisément dans le compilateur Microsoft Visual Studio, vous pouvez (lorsqu'il est compilé pour x86 32 bits). Mais comment savoir si votre processeur a un registre «eax»? Pensez aux processeurs ARM des téléphones portables, aux processeurs x64, etc. Ils n'ont pas «eax». Le processeur MIPS n'a même pas la commande 'mov'
DanielHsH
4

Basé sur d'autres réponses, mais celle-ci rejettera les programmes avec des littéraux binaires illégaux. Les zéros non significatifs sont facultatifs.

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

Exemple:

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

Le "type" d'un nombre binaire est le même que tout nombre décimal, hexadécimal ou octal: int(ou même char, short, long long).

Lorsque vous attribuez une constante, vous ne pouvez pas l'affecter avec 11011011 (curieusement et malheureusement), mais vous pouvez utiliser hex. Hex est un peu plus facile à traduire mentalement. Couper en quartets (4 bits) et traduire en un caractère en [0-9a-f].

Stephen
la source
2

Vous pouvez utiliser un ensemble de bits

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

J'ai prolongé la bonne réponse donnée par @ renato-chandelier en assurant le soutien de:

  • _NIBBLE_(…) - 4 bits, 1 quartet comme argument
  • _BYTE_(…) - 8 bits, 2 quartets comme arguments
  • _SLAB_(…) - 12 bits, 3 grignotages comme arguments
  • _WORD_(…) - 16 bits, 4 grignotages comme arguments
  • _QUINTIBBLE_(…) - 20 bits, 5 grignotages comme arguments
  • _DSLAB_(…) - 24 bits, 6 grignotages comme arguments
  • _SEPTIBBLE_(…) - 28 bits, 7 grignotages comme arguments
  • _DWORD_(…) - 32 bits, 8 quartets comme arguments

Je ne suis pas si sûr des termes «quintibble» et «septibble». Si quelqu'un connaît une alternative, faites-le moi savoir.

Voici la macro réécrite:

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

Et voici l'exemple d'utilisation de 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
la source
0

Utilisez simplement la bibliothèque standard en C ++:

#include <bitset>

Vous avez besoin d'une variable de type std::bitset:

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

Dans cet exemple, j'ai stocké la forme binaire de 10in x.

8uldéfinit la taille de vos bits, 7ulsignifie donc sept bits et ainsi de suite.

Hadi Rasekh
la source
-1

C ++ fournit un modèle standard nommé std::bitset. Essayez-le si vous le souhaitez.

Summer_More_More_Tea
la source
-9

Vous pouvez essayer d'utiliser un tableau de bool:

bool i[8] = {0,0,1,1,0,1,0,1}
George Wagenknecht
la source
2
Beaucoup de votes négatifs, aucune explication. Voici votre explication: stackoverflow.com/questions/2064550/c-why-bool-is-8-bits-long De plus, chaque élément d'un tableau est à une adresse mémoire différente. Mais nous voulons une séquence de 1 et de 0 emballés à une adresse.
JMI MADISON