¿Puedo usar un literal binario en C o C ++?

191

Necesito trabajar con un número binario.

Traté de escribir:

const x = 00010000;

Pero no funcionó.

Sé que puedo usar un número hexadecimal que tiene el mismo valor que 00010000, pero quiero saber si hay un tipo en C ++ para números binarios y si no lo hay, ¿hay otra solución para mi problema?

hamza
fuente
51
Sabes que 00010000es octal, ¿verdad? (Y a su declaración le falta un tipo.)
Keith Thompson
Aquí de manera moderna usando literales C ++.
Lol4t0
2
C ++ 14 agregó una característica para esto. Vea mi nueva respuesta para más detalles en la parte inferior. Por supuesto, requiere un compilador que lo implemente.
lpapp
1
@FormlessCloud: Estas son las reglas de sintaxis proporcionadas en los estándares C y C ++ ( 0bsolo aparece en C ++ 14). Están diseñados para ser inequívocos.
Keith Thompson
2
Posible duplicado de literales binarios?
MJ Rayburn

Respuestas:

70

Puede usarBOOST_BINARY mientras espera C ++ 0x. :) BOOST_BINARYposiblemente tenga una ventaja sobre la implementación de la plantilla en la medida en que también se puede usar en programas en C (es 100% controlado por un preprocesador).

Para hacerlo a la inversa (es decir, imprimir un número en formato binario), se puede utilizar la no portátil itoafunción , o implementar su propio .

Desafortunadamente, no puede formatear en base 2 con secuencias STL (ya setbaseque solo honrará las bases 8, 10 y 16), pero puede usar una std::stringversión de itoa(o la más concisa, pero marginalmente menos eficiente) 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;
}

produce:

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

También lea The String Formatters de Manor Farm de Herb Sutter para una discusión interesante.

vladr
fuente
2
Como dice la página a la que se vincula, solo puede usar 8, 10 o 16 con setbase. Sin embargo:int main() { cout << bitset<8>(42); }
@Roger, gracias por el bitsetconsejo, ya corrigí un poco setbaseantes de ver tu comentario.
vladr
Aquí hay un tutorial sobre literales definidos por el usuario en c ++ 11: akrzemi1.wordpress.com/2012/10/23/user-defined-literals-part-ii . Evidentemente, c ++ 1y (también conocido como c ++ 14) incluirá literales binarios en el estándar.
cheshirekow
275

Si está utilizando GCC, puede utilizar una extensión de GCC (que se incluye en el estándar C ++ 14 ) para esto:

int x = 0b00010000;
qrdl
fuente
2
Varios otros compiladores tienen esta u otras formas similares de expresar números en la base 2.
nategoose
44
Sería bueno tener esto estandarizado, pero clang admite la misma notación.
polemon
14
Funciona en Clang, GCC y TCC. No funciona en PCC. No tengo ningún otro compilador para probar.
Michas
66
He visto varios compiladores de sistemas integrados que lo admiten. No conozco ninguna razón en particular para que no sea una característica de lenguaje estándar.
supercat
55
@polemon open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3472.pdf (C ++ 14.)
Jonathan Baldwin
98

Puedes usar literales binarios. Están estandarizados en C ++ 14. Por ejemplo,

int x = 0b11000;

Apoyo en CCG

El soporte en GCC comenzó en GCC 4.3 (consulte https://gcc.gnu.org/gcc-4.3/changes.html ) como extensiones de la familia del lenguaje C (consulte https://gcc.gnu.org/onlinedocs/gcc/ C-Extensions.html # C-Extensions ), pero desde GCC 4.9 ahora se reconoce como una característica de C ++ 14 o una extensión (consulte ¿ Diferencia entre literales binarios de GCC y C ++ 14? )

Soporte en Visual Studio

El soporte en Visual Studio comenzó en Visual Studio 2015 Preview (consulte https://www.visualstudio.com/news/vs2015-preview-vs#C++ ).

Mohamed El-Nakib
fuente
55
Puede usar 'para separar cada parte: "0b0000'0100'0100'0001
camino
1
@camino Nice, puedes perder el primero "
Nikos
Esta debería ser la respuesta aceptada. La mayoría de las otras respuestas están tan desactualizadas.
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';

El dígito más a la izquierda del literal todavía tiene que ser 1, pero no obstante.

Wilhelmtell
fuente
44
Mejor versión: bitbucket.org/kniht/scraps/src/tip/cpp/binary.hpp ( binary<10>::value == binary<010>::valuey algunas comprobaciones de errores)
De alguna manera me perdí esta antes de publicar mi propia respuesta casi idéntica. Pero en el mío, el dígito principal debe ser 0, no 1.
Mark Ransom
44
Una mejor versión de esta idea de plantilla: code.google.com/p/cpp-binary-constants
Valentin Galea
@ValentinGalea: ¿por qué la versión de Google es mejor que esta?
AJed
Esto es realmente impresionante. Lástima que no funcione para una gran cantidad de bits.
The Quantum Physicist
31

Algunos compiladores (generalmente los de microcontroladores ) tienen una característica especial implementada dentro del reconocimiento de números binarios literales con el prefijo "0b ..." que precede al número, aunque la mayoría de los compiladores (estándares C / C ++) no tienen esa característica y si es el caso, aquí está mi solución alternativa:

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

Desventajas (no es tan grande):

  • Los números binarios deben agruparse 4 por 4;
  • Los literales binarios tienen que ser solo números enteros sin signo;

Ventajas :

  • Preprocesador total dirigido, no spending processor timeen operaciones sin sentido ( like "?.. :..", "<<", "+") al programa ejecutable (se puede realizar cientos de veces en la aplicación final);
  • Funciona "mainly in C"compiladores y C ++ también ( template+enum solution works only in C++ compilers);
  • Solo tiene la limitación de "longitud" para expresar valores "constantes literales". Habría habido una limitación de longitud temprana (generalmente 8 bits: 0-255) si se hubieran expresado valores constantes al analizar la resolución de"enum solution" (usually 255 = reach enum definition limit) , de manera diferente, las limitaciones "constantes literales", en el compilador permite números mayores;
  • Algunas otras soluciones exigen un número exagerado de definiciones constantes (en mi opinión, demasiadas definiciones) que incluyen largas o several header files(en la mayoría de los casos no son fácilmente legibles y comprensibles, y hacen que el proyecto se confunda y extienda innecesariamente, por ejemplo "BOOST_BINARY()");
  • Simplicidad de la solución: fácil de leer, comprensible y ajustable para otros casos (podría extenderse para agrupar 8 por 8 también);
Araña Renato
fuente
¿Por qué, por ejemplo, B_0100no se usa (en lugar de 0100)? Como en eg char b = BYTE(0100,0001);.
Peter Mortensen
@PeterMortensen La _B2Hfunción de preprocesador agrega B_ .
mxmlnkn
20

Este hilo puede ayudar.

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

¡Funciona! (Todos los créditos van a Tom Torfs).

Federico A. Ramponi
fuente
Yo realmente no entiendo (principiante ima en la programación y especialmente en C ++), pero parece interesante así que voy a tratar de entender que después de algunos más estudios C ++, gracias
Hamza
3
La macro B8 funciona convirtiendo el literal "binario" en un literal hexadecimal y extrayendo cada cuarto bit.
dan04
Me pregunto qué significa 0x ## n ## LU. Nunca encontré tal sintaxis.
Federico A. Ramponi
@hamza: de hecho es bastante complejo. Pero lo que necesita comprender es solo desde #include <stdio> en adelante.
Federico A. Ramponi
8
@Federico: el ##operador del preprocesador pega los tokens juntos. Entonces, en este caso, si llamas HEX__(10), se expande a 0x10LU.
James McNellis
18

Como ya se respondió, los estándares C no tienen forma de escribir directamente números binarios. Sin embargo, hay extensiones del compilador, y aparentemente C ++ 14 incluye el 0bprefijo para binario. (Tenga en cuenta que esta respuesta se publicó originalmente en 2010.)

Una solución popular es incluir un archivo de encabezado con macros auxiliares . Una opción fácil también es generar un archivo que incluya definiciones de macro para todos los patrones de 8 bits, por ejemplo:

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

Esto da como resultado solo 256 #defines, y si se necesitan constantes binarias de más de 8 bits, estas definiciones se pueden combinar con desplazamientos y OR, posiblemente con macros auxiliares (por ejemplo, BIN16(B00000001,B00001010)). (Tener macros individuales para cada valor de 16 bits, y mucho menos de 32 bits, no es plausible).

Por supuesto, la desventaja es que esta sintaxis requiere escribir todos los ceros a la izquierda, pero esto también puede aclararlo para usos como establecer banderas de bits y contenido de registros de hardware. Para una macro similar a una función que resulta en una sintaxis sin esta propiedad, vea el bithacks.henlace anterior.

Arkku
fuente
2
Entonces, ¿qué tamaño tendría que leer el CPP si tuviera todas las macros para un long long int?
wilhelmtell
3
@wilhelmtell: ¿Y cuál es la relevancia de eso cuando especifiqué "todos los patrones de 8 bits " (= 256 líneas) y sugerí combinar cantidades mayores de esos? Incluso el BOOST_BINARY de la respuesta aceptada define todos los patrones de 8 bits en el encabezado ...
Arkku
16

La mentalidad de sobre ingeniería de C ++ ya está bien explicada en las otras respuestas aquí. Aquí está mi intento de hacerlo con una mentalidad C, keep-it-simple-ffs:

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

C no tiene notación nativa para números binarios puros. Su mejor apuesta aquí sería octal (p 07777. Ej. ) De hexadecimal (p 0xfff. Ej .).

Nikolai Fetissov
fuente
11

Puede usar la función que se encuentra en esta pregunta para obtener hasta 22 bits en C ++. Aquí está el código del enlace, editado adecuadamente:

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

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

Entonces puedes hacer algo como binary<0101011011>::value.

Mark Ransom
fuente
7

La unidad más pequeña con la que puede trabajar es un byte (que es de chartipo). Sin embargo, puede trabajar con bits utilizando operadores bit a bit.

En cuanto a los literales enteros, solo puede trabajar con números decimales (base 10), octales (base 8) o hexadecimales (base 16). No hay literales binarios (base 2) en C ni C ++.

Los números octales tienen el prefijo 0y los números hexadecimales tienen el prefijo 0x. Los números decimales no tienen prefijo.

En C ++ 0x podrás hacer lo que quieras a través de literales definidos por el usuario .

Brian R. Bondy
fuente
¿puedo al menos mostrar el valor binario de un hexadecimal en una función print o cout?
hamza
Sí, puedes <shameless_plug> stackoverflow.com/questions/2611764#2611883 </shameless_plug>
vladr
55
Algunos compiladores de C admiten 0b100101 para literales binarios, pero desafortunadamente es una extensión no estándar.
Joey Adams
3
Tenga en cuenta que, si bien no está definido en el estándar, algunos compiladores (especialmente los para microcontroladores y sistemas integrados) agregan la sintaxis para binario en el formulario 0b00101010como una conveniencia. SDCC es uno, y estoy seguro de que hay otros que también lo hacen. (Editar: Ja, ¡golpéame, @Joey!)
Matt B.
5

También puede usar un ensamblaje en línea como este:

int i;

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

std::cout << i;

De acuerdo, puede ser algo exagerado, pero funciona.

renger
fuente
3
Su solución no es multiplataforma. En muchas arquitecturas, no puede incluir el código de ensamblaje en C. Específicamente en el compilador de Microsoft Visual Studio puede (cuando se compila para x86 32bits). Pero, ¿cómo saber si su procesador tiene un registro 'eax'? Piense en procesadores ARM en teléfonos móviles, procesadores x64, etc. No tienen 'eax'. El procesador MIPS ni siquiera tiene el comando 'mov'
DanielHsH
4

Basado en algunas otras respuestas, pero esta rechazará programas con literales binarios ilegales. Los ceros iniciales son opcionales.

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

Ejemplo:

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

El "tipo" de un número binario es el mismo que cualquier número decimal, hexadecimal u octal: int (o incluso char, short, long long).

Cuando asigna una constante, no puede asignarla con 11011011 (curiosa y desafortunadamente), pero puede usar hexadecimal. El maleficio es un poco más fácil de traducir mentalmente. Trocear en nibbles (4 bits) y traducir a un carácter en [0-9a-f].

Stephen
fuente
2

Puedes usar un bitset

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

Extendí la buena respuesta dada por @ renato-chandelier asegurando el apoyo de:

  • _NIBBLE_(…) - 4 bits, 1 mordisco como argumento
  • _BYTE_(…) - 8 bits, 2 mordiscos como argumentos
  • _SLAB_(…) - 12 bits, 3 mordiscos como argumentos
  • _WORD_(…) - 16 bits, 4 mordiscos como argumentos
  • _QUINTIBBLE_(…) - 20 bits, 5 mordiscos como argumentos
  • _DSLAB_(…) - 24 bits, 6 mordiscos como argumentos
  • _SEPTIBBLE_(…) - 28 bits, 7 mordiscos como argumentos
  • _DWORD_(…) - 32 bits, 8 mordiscos como argumentos

En realidad, no estoy tan seguro acerca de los términos "quintibble" y "septibble". Si alguien conoce alguna alternativa, hágamelo saber.

Aquí está la macro reescrita:

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

Y aquí está el ejemplo 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
fuente
0

Simplemente use la biblioteca estándar en C ++:

#include <bitset>

Necesita una variable de tipo std::bitset:

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

En este ejemplo, almacené la forma binaria de 10in x.

8uldefine el tamaño de sus bits, por lo que 7ulsignifica siete bits y así sucesivamente.

Hadi Rasekh
fuente
-1

C ++ proporciona una plantilla estándar llamada std::bitset. Pruébalo si quieres.

Summer_More_More_Tea
fuente
-9

Podría intentar usar una matriz de bool:

bool i[8] = {0,0,1,1,0,1,0,1}
George Wagenknecht
fuente
2
Muchos votos negativos, sin explicación. Aquí está su explicación: stackoverflow.com/questions/2064550/c-why-bool-is-8-bits-long Además, cada elemento en una matriz está en una dirección de memoria diferente. Pero queremos una secuencia de 1 y 0 empaquetados en una dirección.
JMI MADISON