web-dev-qa-db-fra.com

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

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 ayant 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, existe-t-il une autre solution à mon problème ?

180
hamza

Vous pouvez tiliser BOOST_BINARY en attendant C++ 0x. :) _BOOST_BINARY_ a incontestablement un avantage sur l’implémentation du modèle dans la mesure où il peut également être utilisé dans les programmes C (100% préprocesseur conduit.)

MISE À JOUR

Pour faire l’inverse (c’est-à-dire imprimer un nombre sous forme binaire), vous pouvez utiliser le non-portable fonction itoa , ou implémentez le vôtre .

Malheureusement, vous ne pouvez pas formater en base 2 avec des flux STL (puisque setbase respectera uniquement les bases 8, 10 et 16), mais vous pouvez utiliser soit un _std::string_ version de itoa, ou (le plus concis, mais légèrement moins efficace) _std::bitset_.

(Merci Roger pour le conseil 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 Herb Sutter Les formateurs de chaîne de Manor Farm pour une discussion intéressante.

69
vladr

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

int x = 0b00010000;
253
qrdl

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

int x = 0b11000;

Support dans GCC

La prise en charge dans 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 langues 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 C++ 14? )

Support dans Visual Studio

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

80
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.

73
wilhelmtell

Quelques compilateurs (généralement ceux de microcontrôleurs ) ont une particularité de reconnaître les nombres binaires littéraux par préfixe "0b ..." précédant le nombre, bien que la plupart des compilateurs ( Les standards C/C++) n’ont pas cette fonctionnalité et si c’est le cas, c’est là 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 :

  • Total dirigé par le préprocesseur, pas spending processor time dans les opérations sans objet (like "?.. :..", "<<", "+") au programme exécutable (il peut être exécuté des centaines de fois dans l'application finale);
  • Cela fonctionne "mainly in C" compilateurs et C++ ainsi (template+enum solution works only in C++ compilers);
  • Il n'y a que la limitation de "longness" pour exprimer des valeurs de "constante littérale". Il y aurait eu une limite précoce de longness (généralement 8 bits: 0-255) si on avait exprimé des valeurs constantes en analysant la résolution de "enum solution" (usually 255 = reach enum definition limit), autrement, les limitations de "constante littérale" dans le compilateur autorisent des nombres plus grands;
  • Certaines autres solutions exigent un nombre exagéré de définitions constantes (trop de définitions à mon avis), y compris long ou several header files (dans la plupart des cas difficilement lisible et compréhensible, et rendent le projet inutilement confus et étendu, comme celui qui utilise "BOOST_BINARY()") ;
  • Simplicité de la solution: facilement lisible, compréhensible et réglable pour les autres cas (pourrait être étendu pour le groupe 8 sur 8 également);
30
Renato Chandelier

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

20

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

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

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

Cela donne seulement 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 auxiliaires (par exemple, BIN16(B00000001,B00001010)). (Avoir des macros individuelles pour chaque valeur 16 bits, encore moins 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 générant une syntaxe sans cette propriété, voir le lien bithacks.h ci-dessus.

15
Arkku

La mentalité de sur-ingénierie C++ est déjà bien expliquée dans les autres réponses données ici. Voici ma tentative de le faire avec un état d'esprit C, Keep-It-Simple-Ffs:

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

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

12
Nikolai Fetissov

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

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

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

Donc, vous pouvez faire quelque chose comme binary<0101011011>::value.

9
Mark Ransom

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

En ce qui concerne 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 portent le préfixe 0 et les nombres hexadécimaux le préfixe 0x. Les nombres décimaux n'ont pas de préfixe.

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

7
Brian R. Bondy

Basé sur d'autres réponses, mais celle-ci rejettera les programmes contenant des littéraux binaires illégaux. Les zéros au début 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;
}
4
Thomas Eding

Vous pouvez également utiliser inline Assembly comme ceci:

int i;

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

std::cout << i;

Ok, c'est peut-être un peu exagéré, mais ça marche :)

2
renger

Le "type" d'un nombre binaire est identique à tout nombre décimal, hexadécal ou octal: int (ou même car, court, long long).

Lorsque vous affectez 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. Morceau en petits morceaux (4 bits) et traduit en un caractère dans [0-9a-f].

2
Stephen

Vous pouvez utiliser un bitet

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

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

  • _NIBBLE_(…) - 4 bits, 1 quartet en argument
  • _BYTE_(…) - 8 bits, 2 nœuds comme arguments
  • _SLAB_(…) - 12 bits, 3 noeuds comme arguments
  • _Word_(…) - 16 bits, 4 nœuds comme arguments
  • _QUINTIBBLE_(…) - 20 bits, 5 octets comme arguments
  • _DSLAB_(…) - 24 bits, 6 octets comme arguments
  • _SEPTIBBLE_(…) - 28 bits, 7 octets comme arguments
  • _DWORD_(…) - 32 bits, 8 octets comme arguments

En réalité, je ne suis pas sûr des termes “quintibble” et “septibble”. Si quelqu'un connaît une alternative s'il vous plaît 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 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; */
2
madmurphy

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é un binaire de 10 dans x.

8ul définit la taille de vos bits, donc 7ul signifie sept bits et ainsi de suite.

0
Hadi Rasekh