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 ?
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.)
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.
Si vous utilisez GCC, vous pouvez utiliser ne extension GCC (incluse dans la norme C++ 14 ) pour cela:
int x = 0b00010000;
Vous pouvez utiliser des littéraux binaires. Ils sont normalisés en C++ 14. Par exemple,
int x = 0b11000;
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? )
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++ ).
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.
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):
Avantages :
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);"mainly in C"
compilateurs et C++ ainsi (template+enum solution works only in C++ compilers
);"enum solution" (usually 255 = reach enum definition limit)
, autrement, les limitations de "constante littérale" dans le compilateur autorisent des nombres plus grands;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()"
) ;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.)
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 #define
s, 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.
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
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
).
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
.
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 .
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;
}
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 :)
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].
Vous pouvez utiliser un bitet
bitset<8> b(string("00010000"));
int i = (int)(bs.to_ulong());
cout<<i;
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 argumentsEn 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; */
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.