siguiente - separadores en c++
¿Puedo usar un literal binario en C o C++? (19)
Algunos compiladores (generalmente los de microcontrollers ) tienen una característica especial implementada para reconocer números binarios literales por el prefijo "0b ..." que precede al número, aunque la mayoría de los compiladores (estándares C / C ++) no tienen dicha 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 son tan grandes):
- Los números binarios deben agruparse 4 por 4;
- Los literales binarios deben ser solo números enteros sin signo;
Ventajas :
- Impulso total del preprocesador, no
spending processor time
en operaciones sin sentido (like "?.. :..", "<<", "+"
) en el programa ejecutable (puede realizarse cientos de veces en la aplicación final); - Funciona
"mainly in C"
compiladores"mainly in C"
y C ++ también (latemplate+enum solution works only in C++ compilers
); - Tiene solo la limitación de "longitud" para expresar valores "constantes literales". Habría habido una limitación de longitud anticipada (generalmente 8 bits: 0-255) si uno hubiera expresado valores constantes al analizar la resolución de
"enum solution" (usually 255 = reach enum definition limit)
, de manera diferente, limitaciones de "constante literal", en el el compilador permite números mayores; - Algunas otras soluciones exigen un número exagerado de definiciones constantes (en mi opinión, demasiadas), incluidos
several header files
largos oseveral header files
(en la mayoría de los casos no fáciles de leer y comprensibles, y hacen que el proyecto se confunda y extienda innecesariamente, como el que usa"BOOST_BINARY()"
); - Simplicidad de la solución: fácil de leer, comprensible y ajustable para otros casos (podría ampliarse para agrupar 8 por 8 también);
Necesito trabajar con un número binario.
Intenté escribir:
const x = 00010000;
Pero no funcionó.
Sé que puedo usar un número hexadecimal que tenga el mismo valor que 00010000
, pero quiero saber si hay un tipo en C ++ para números binarios y si no existe, ¿hay alguna otra solución para mi problema?
Basado en algunas otras respuestas, pero este rechazará programas con literales binarios ilegales. Los ceros a la izquierda 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;
}
C ++ proporciona una plantilla estándar llamada bitset
. Pruébalo si quieres.
C no tiene notación nativa para números binarios puros. Su mejor apuesta aquí sería octal (por ejemplo, 07777
) de hexadecimal (por ejemplo, 0xfff
).
Como ya se respondió, los estándares C no tienen forma de escribir directamente números binarios. Sin embargo, hay extensiones de compilador y aparentemente C ++ 14 incluye el prefijo 0b
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 de ayuda . 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 #define
s, y si se necesitan constantes binarias de más de 8 bits, estas definiciones se pueden combinar con cambios y OR, posiblemente con macros de ayuda (p. Ej., BIN16(B00000001,B00001010)
). (Tener macros individuales por 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 hacerlo más claro para usos como el establecimiento de indicadores de bits y el contenido de los registros de hardware. Para una macro similar a una función que da como resultado una sintaxis sin esta propiedad, vea bithacks.h
vinculado arriba.
El "tipo" de un número binario es el mismo que cualquier número decimal, hexadecimal u octal: int
(o incluso char, corto, largo).
Cuando asigna una constante, no puede asignarla con 11011011 (curiosa y desafortunadamente), pero puede usar hexadecimal. Hex es un poco más fácil de traducir mentalmente. Divide en nibbles (4 bits) y traduce a un personaje en [0-9a-f].
Extendí la buena respuesta dada por @ renato-chandelier al garantizar el soporte de:
-
_NIBBLE_(…)
- 4 bits, 1 mordisco como argumento -
_BYTE_(…)
- 8 bits, 2 nibbles como argumentos -
_SLAB_(…)
- 12 bits, 3 mordiscos como argumentos -
_WORD_(…)
- 16 bits, 4 nibbles como argumentos -
_QUINTIBBLE_(…)
- 20 bits, 5 nibbles como argumentos -
_DSLAB_(…)
- 24 bits, 6 nibbles como argumentos -
_SEPTIBBLE_(…)
- 28 bits, 7 nibbles como argumentos -
_DWORD_(…)
- 32 bits, 8 nibbles como argumentos
De hecho, no estoy tan seguro de los términos "quintibble" y "septibble". Si alguien conoce alguna alternativa, por favor avíseme.
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 uso 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; */
La mentalidad de sobreingenierí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
La unidad más pequeña con la que puede trabajar es un byte (que es de tipo char
). 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 en C ++.
Los números octales tienen el prefijo 0
y los números hexadecimales tienen el prefijo 0x
. Los números decimales no tienen prefijo.
En C ++ 0x, podrás hacer lo que quieras por cierto a través de los literales definidos por el usuario .
Puede usar BOOST_BINARY
mientras espera C ++ 0x. :) BOOST_BINARY
podría tener una ventaja sobre la implementación de la plantilla en la medida en que también se puede usar en los programas C (es 100% preprocesador).
ACTUALIZAR
Para hacer lo contrario (es decir, imprimir un número en forma binaria), puede usar la función itoa
no portátil o implementar la suya propia .
Desafortunadamente no se puede hacer el formato base 2 con transmisiones STL (ya que setbase
solo respetará las bases 8, 10 y 16), pero puede usar una versión std::string
de itoa
, o (la más concisa, pero marginalmente menos eficiente) std::bitset
.
(¡Gracias, Roger por la 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
Lea también The String Formatters de Herb Sutter de Manor Farm para una discusión interesante.
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 puede hacer algo como binary<0101011011>::value
.
Puedes usar literales binarios. Están estandarizados en C ++ 14. Por ejemplo,
int x = 0b11000;
Soporte en GCC
El soporte en GCC comenzó en GCC 4.3 (ver https://gcc.gnu.org/gcc-4.3/changes.html ) como extensiones para la familia de lengua C (ver 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 como una extensión (consulte ¿ Diferencia entre los literales binarios de GCC y los de 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++ ).
Puedes usar un conjunto de bits
bitset<8> b(string("00010000"));
int i = (int)(bs.to_ulong());
cout<<i;
Si está utilizando GCC, puede usar una extensión GCC (que está incluida en el estándar C ++ 14 ) para esto:
int x = 0b00010000;
Solo 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é binarios de 10 en x.
8ul
define el tamaño de tus bits, por lo que 7ul
significa siete bits y así sucesivamente.
También puede usar un ensamblado en línea como este:
int i;
__asm {
mov eax, 00000000000000000000000000000000b
mov i, eax
}
std::cout << i;
De acuerdo, podría ser algo exagerado, pero funciona :)
Tu podrías intentar:
bool i[8] = {0,0,1,1,0,1,0,1}
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).
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.