Literales binarios?

En el código, a veces veo que las personas especifican constantes en formato hexadecimal como este:

const int has_nukes = 0x0001; const int has_bio_weapons = 0x0002; const int has_chem_weapons = 0x0004; // ... int arsenal = has_nukes | has_bio_weapons | has_chem_weapons; // all of them if(arsenal &= has_bio_weapons){ std::cout << "BIO!!" } 

Pero no tiene sentido para mí usar el formato hexadecimal aquí. ¿Hay alguna forma de hacerlo directamente en binario? Algo como esto:

 const int has_nukes = 0b00000000000000000000000000000001; const int has_bio_weapons = 0b00000000000000000000000000000010; const int has_chem_weapons = 0b00000000000000000000000000000100; // ... 

Sé que los comstackdores C / C ++ no comstackrán esto, pero debe haber una solución alternativa? ¿Es posible en otros lenguajes como Java?

Yo usaría un operador de desplazamiento de bits:

 const int has_nukes = 1<<0; const int has_bio_weapons = 1<<1; const int has_chem_weapons = 1<<2; // ... int dangerous_mask = has_nukes | has_bio_weapons | has_chem_weapons; bool is_dangerous = (country->flags & dangerous_mask) == dangerous_mask; 

Es incluso mejor que una inundación de 0.

En C ++ 14, podrá usar literales binarios con la siguiente syntax:

 0b010101010 /* more zeros and ones */ 

Esta característica ya está implementada en los últimos clang y gcc . Puede intentarlo si ejecuta esos comstackdores con la -std=c++1y .

Por cierto, la próxima versión de C ++ admitirá literales definidos por el usuario. Ya están incluidos en el borrador de trabajo. Esto permite ese tipo de cosas (ojalá no tenga demasiados errores):

 template constexpr int operator "" _b() { return conv2bin::value; } int main() { int const v = 110110110_b; } 

conv2bin sería una plantilla como esta:

 template struct conv2bin; template struct conv2bin { static_assert(high == '0' || high == '1', "no bin num!"); static int const value = (high - '0') * (1 << sizeof...(digits)) + conv2bin::value; }; template struct conv2bin { static_assert(high == '0' || high == '1', "no bin num!"); static int const value = (high - '0'); }; 

Bueno, lo que obtenemos son literales binarios que ya se evalúan completamente en tiempo de comstackción, debido al “constexpr” anterior. Lo anterior usa un tipo de retorno int duro. Creo que uno podría incluso hacer depender la longitud de la cadena binaria. Está utilizando las siguientes características, para cualquier persona interesada:

  • Expresiones constantes generalizadas.
  • Plantillas variables Una breve introducción se puede encontrar aquí
  • Afirmaciones estáticas (static_assert)
  • Literals definidos por el usuario

En realidad, el tronco actual de GCC ya implementa plantillas variadas y aserciones estáticas. Esperemos que apoye a los otros dos pronto. Creo que C ++ 1x sacudirá la casa.

La biblioteca estándar de C ++ es tu amiga:

 #include  const std::bitset <32> has_nukes( "00000000000000000000000000000001" ); 

Puedes usar << si quieres.

 int hasNukes = 1; int hasBioWeapons = 1 << 1; int hasChemWeapons = 1 << 2; 

GCC admite constantes binarias como una extensión desde 4.3. Vea el anuncio (mire la sección “Nuevos idiomas y mejoras específicas del idioma”).

Esta discusión puede ser interesante … Podría haber sido, ya que el enlace está muerto por desgracia. Describió un enfoque basado en plantillas similar a otras respuestas aquí.

Y también hay una cosa llamada BOOST_BINARY .

El término que quieres son literales binarios

Ruby los tiene con la syntax que le das.

Una alternativa es definir macros de ayuda para convertir para usted. Encontré el siguiente código en http://bytes.com/groups/c/219656-literal-binary

 /* Binary constant generator macro * By Tom Torfs - donated to the public domain */ /* All macro's evaluate to compile-time constants */ /* *** helper macros *** */ /* turn a numeric literal into a hex constant * (avoids problems with leading zeroes) * 8-bit constants max value 0x11111111, always fits in unsigned long */ #define HEX_(n) 0x##n##LU /* 8-bit conversion function */ #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 *** / /* for upto 8-bit binary constants */ #define B8(d) ((unsigned char) B8_(HEX_(d))) /* for upto 16-bit binary constants, MSB first */ #define B16(dmsb, dlsb) (((unsigned short) B8(dmsb) << 8) \ | B8(dlsb)) /* for upto 32-bit binary constants, MSB first */ #define B32(dmsb, db2, db3, dlsb) (((unsigned long) B8(dmsb) << 24) \ | ((unsigned long) B8( db2) << 16) \ | ((unsigned long) B8( db3) << 8) \ | B8(dlsb)) /* Sample usage: * B8(01010101) = 85 * B16(10101010,01010101) = 43605 * B32(10000000,11111111,10101010,01010101) = 2164238933 */ 

La próxima versión de C ++, C ++ 0x, introducirá literales definidos por el usuario . No estoy seguro de si los números binarios serán parte del estándar, pero en el peor de los casos podrá habilitarlo usted mismo:

 int operator "" _B(int i); assert( 1010_B == 10); 

Escribo literales binarios como este:

 const int has_nukes = 0x0001; const int has_bio_weapons = 0x0002; const int has_chem_weapons = 0x0004; 

Es más compacto que la notación sugerida y más fácil de leer. Por ejemplo:

 const int upper_bit = 0b0001000000000000000; 

versus:

 const int upper_bit = 0x04000; 

¿Notaste que la versión binaria no era un múltiplo par de 4 bits? ¿Pensaste que era 0x10000?

Con un poco de práctica, el hexágono u octal es más fácil para un ser humano que binario. Y, en mi opinión, es más fácil de leer que usar operadores de turno. Pero concedo que mis años de trabajo en lenguaje ensamblador pueden sesgarme en ese punto.

Java tampoco admite literales binarios, desafortunadamente. Sin embargo, tiene enumeraciones que se pueden usar con un EnumSet . Un EnumSet representa valores enum internamente con campos de bits, y presenta una interfaz Set para manipular estos indicadores.

Alternativamente, puede usar desplazamientos de bits (en decimal) al definir sus valores:

 const int HAS_NUKES = 0x1 << 0; const int HAS_BIO_WEAPONS = 0x1 << 1; const int HAS_CHEM_WEAPONS = 0x1 << 2; 

No hay syntax para las constantes binarias literales en C ++ de la misma forma que para hexadecimal y octal. Lo más parecido a lo que parece que estás tratando de hacer sería aprender y usar bitset .

Como un aparte:

Especialmente si se trata de un conjunto grande, en lugar de pasar por el esfuerzo mental [menor] de escribir una secuencia de cantidades de desplazamiento, puede hacer que cada constante dependa de la constante definida anteriormente:

 const int has_nukes = 1; const int has_bio_weapons = has_nukes << 1; const int has_chem_weapons = has_bio_weapons << 1; const int has_nunchuks = has_chem_weapons << 1; // ... 

Parece un poco redundante, pero es menos propenso a errores tipográficos. Además, puede simplemente insertar una nueva constante en el medio sin tener que tocar ninguna otra línea, excepto la que le sigue inmediatamente:

 const int has_nukes = 1; const int has_gravity_gun = has_nukes << 1; // added const int has_bio_weapons = has_gravity_gun << 1; // changed const int has_chem_weapons = has_bio_weapons << 1; // unaffected from here on const int has_nunchuks = has_chem_weapons << 1; // ... 

Comparar con:

 const int has_nukes = 1 << 0; const int has_bio_weapons = 1 << 1; const int has_chem_weapons = 1 << 2; const int has_nunchuks = 1 << 3; // ... const int has_scimatar = 1 << 28; const int has_rapier = 1 << 28; // good luck spotting this typo! const int has_katana = 1 << 30; 

Y:

 const int has_nukes = 1 << 0; const int has_gravity_gun = 1 << 1; // added const int has_bio_weapons = 1 << 2; // changed const int has_chem_weapons = 1 << 3; // changed const int has_nunchuks = 1 << 4; // changed // ... // changed all the way const int has_scimatar = 1 << 29; // changed *sigh* const int has_rapier = 1 << 30; // changed *sigh* const int has_katana = 1 << 31; // changed *sigh* 

Aparte de mi lado, probablemente sea igualmente difícil detectar un error tipográfico como este:

 const int has_nukes = 1; const int has_gravity_gun = has_nukes << 1; const int has_bio_weapons = has_gravity_gun << 1; const int has_chem_weapons = has_gravity_gun << 1; // oops! const int has_nunchuks = has_chem_weapons << 1; 

Por lo tanto, creo que la principal ventaja de esta syntax en cascada es cuando se trata de inserciones y eliminaciones de constantes.

Otro método:

 template class b { public: static unsigned int const x = N; typedef b_<0> _0000; typedef b_<1> _0001; typedef b_<2> _0010; typedef b_<3> _0011; typedef b_<4> _0100; typedef b_<5> _0101; typedef b_<6> _0110; typedef b_<7> _0111; typedef b_<8> _1000; typedef b_<9> _1001; typedef b_<10> _1010; typedef b_<11> _1011; typedef b_<12> _1100; typedef b_<13> _1101; typedef b_<14> _1110; typedef b_<15> _1111; private: template struct b_: public b {}; }; typedef b<0> _0000; typedef b<1> _0001; typedef b<2> _0010; typedef b<3> _0011; typedef b<4> _0100; typedef b<5> _0101; typedef b<6> _0110; typedef b<7> _0111; typedef b<8> _1000; typedef b<9> _1001; typedef b<10> _1010; typedef b<11> _1011; typedef b<12> _1100; typedef b<13> _1101; typedef b<14> _1110; typedef b<15> _1111; 

Uso:

 std::cout << _1101::_1001::_1101::_1101::x; 

Implementado en CityLizard ++ (citylizard / binary / b.hpp) .

Si desea utilizar conjuntos de bits, auto, plantillas variadic, literales definidos por el usuario, static_assert, constexpr y noexcept intente esto:

 template struct __checkbits { static const bool valid = false; }; template struct __checkbits { static const bool valid = (High == '0' || High == '1') && __checkbits::valid; }; template struct __checkbits { static const bool valid = (High == '0' || High == '1'); }; template inline constexpr std::bitset operator"" bits() noexcept { static_assert(__checkbits::valid, "invalid digit in binary string"); return std::bitset((char []){Bits..., '\0'}); } 

Úselo así:

 int main() { auto bits = 0101010101010101010101010101010101010101010101010101010101010101bits; std::cout << bits << std::endl; std::cout << "size = " << bits.size() << std::endl; std::cout << "count = " << bits.count() << std::endl; std::cout << "value = " << bits.to_ullong() << std::endl; // This triggers the static_assert at compile-time. auto badbits = 2101010101010101010101010101010101010101010101010101010101010101bits; // This throws at run-time. std::bitset<64> badbits2("2101010101010101010101010101010101010101010101010101010101010101bits"); } 

Gracias a @ johannes-schaub-litb

Estoy de acuerdo en que es útil tener una opción para literales binarios, y están presentes en muchos lenguajes de progtwigción. En C, he decidido usar una macro como esta:

 #define bitseq(a00,a01,a02,a03,a04,a05,a06,a07,a08,a09,a10,a11,a12,a13,a14,a15, \ a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28,a29,a30,a31) \ (a31|a30<< 1|a29<< 2|a28<< 3|a27<< 4|a26<< 5|a25<< 6|a24<< 7| \ a23<< 8|a22<< 9|a21<<10|a20<<11|a19<<12|a18<<13|a17<<14|a16<<15| \ a15<<16|a14<<17|a13<<18|a12<<19|a11<<20|a10<<21|a09<<22|a08<<23| \ a07<<24|a06<<25|a05<<26|a04<<27|a03<<28|a02<<29|a01<<30|(unsigned)a00<<31) 

El uso es bastante directo =)

Una manera ligeramente horrible de hacerlo es generando un archivo .h con muchas #defines …

 #define b00000000 0 #define b00000001 1 #define b00000010 2 #define b00000011 3 #define b00000100 4 

etc. Esto podría tener sentido para números de 8 bits, pero probablemente no para 16 bits o más.

Alternativamente, haz esto (similar a la respuesta de Zach Scrivena):

 #define bit(x) (1<