¿Cómo imprimo un carácter sin signo como hex en c ++ usando ostream?

Quiero trabajar con variables de 8 bits sin signo en C ++. O unsigned char o uint8_t hacen el truco en lo que respecta a la aritmética (lo que se espera, ya que AFAIK uint8_t es solo un alias para unsigned char , o al menos lo presenta el depurador).

El problema es que si imprimo las variables usando ostream en C ++, lo trata como char. Si tengo:

 unsigned char a = 0; unsigned char b = 0xff; cout << "a is " << hex << a <<"; b is " << hex << b << endl; 

entonces la salida es:

 a is ^@; b is 377 

en lugar de

 a is 0; b is ff 

Intenté usar uint8_t , pero como mencioné antes, eso es typedefed a unsigned char , por lo que hace lo mismo. ¿Cómo puedo imprimir mis variables correctamente?

Editar: hago esto en muchos lugares a lo largo de mi código. ¿Hay alguna forma de que pueda hacer esto sin enviar contenido a int cada vez que quiera imprimir?

    Sugeriría usar la siguiente técnica:

     struct HexCharStruct { unsigned char c; HexCharStruct(unsigned char _c) : c(_c) { } }; inline std::ostream& operator< <(std::ostream& o, const HexCharStruct& hs) { return (o << std::hex << (int)hs.c); } inline HexCharStruct hex(unsigned char _c) { return HexCharStruct(_c); } int main() { char a = 131; std::cout << hex(a) << std::endl; } 

    Es corto para escribir, tiene la misma eficacia que la solución original y le permite elegir usar la salida de caracteres "original". Y es seguro para tipos (no usa macros "malvadas" :-))

    Utilizar:

     cout < < "a is " << hex << (int) a <<"; b is " << hex << (int) b << endl; 

    Y si quieres relleno con ceros a la izquierda, entonces:

     #include  ... cout < < "a is " << setw(2) << setfill('0') << hex << (int) a ; 

    Como estamos utilizando moldes de estilo C, ¿por qué no ir al grano con la maldad terminal de C ++ y usar una macro?

     #define HEX( x ) setw(2) < < setfill('0') << hex << (int)( x ) 

    puedes decir

     cout < < "a is " << HEX( a ); 

    Editar: ¡ Una vez dicho esto, la solución de MartinStettner es mucho mejor!

    Puede leer más sobre esto en http://cpp.indi.frih.net/blog/2014/09/tippet-printing-numeric-values-for-chars-and-uint8_t/ y http: //cpp.indi. frih.net/blog/2014/08/code-critique-stack-overflow-posters-cant-print-the-numeric-value-of-a-char/ . Solo estoy publicando esto porque ha quedado claro que el autor de los artículos anteriores no tiene la intención de hacerlo.

    La técnica más simple y correcta para imprimir un char como hex es

     unsigned char a = 0; unsigned char b = 0xff; auto flags = cout.flags(); //I only include resetting the ioflags because so //many answers on this page call functions where //flags are changed and leave no way to //return them to the state they were in before //the function call cout < < "a is " << hex << +a <<"; b is " << +b << endl; cout.flags(flags); 

    La versión resumida de los lectores de cómo funciona esto es que el operador unario + fuerza una conversión de tipo no op a un int con la firma correcta. Por lo tanto, un char sin signo se convierte en unsigned int, un char firmado se convierte en int, y un char se convierte en unsigned int o int dependiendo de si char está firmado o no en su plataforma (es un shock para muchos que char es especial y no especificado como firmado o sin firmar).

    El único aspecto negativo de esta técnica es que puede no ser obvio lo que le está sucediendo a alguien que no está familiarizado con ella. Sin embargo, creo que es mejor utilizar la técnica correcta y enseñar a otros sobre ella en lugar de hacer algo que sea incorrecto pero que sea más claro inmediatamente.

    Lo haría como MartinStettner pero agrego un parámetro adicional para la cantidad de dígitos:

     inline HexStruct hex(long n, int w=2) { return HexStruct(n, w); } // Rest of implementation is left as an exercise for the reader 

    Entonces tiene dos dígitos por defecto, pero puede establecer cuatro, ocho o lo que sea, si lo desea.

    p.ej.

     int main() { short a = 3142; std:cout < < hex(a,4) << std::endl; } 

    Puede parecer exagerado, pero como dijo Bjarne: "las bibliotecas deberían ser fáciles de usar, no fáciles de escribir".

    Creo que la respuesta de TrungTN y anon está bien, pero la forma de MartinStettner de implementar la función hex () no es realmente simple, y demasiado oscura, considerando que hex < < (int) mychar ya es una solución alternativa.

    aquí está mi solución para hacer que el operador “< <" sea más fácil:

     #include  #include  string uchar2hex(unsigned char inchar) { ostringstream oss (ostringstream::out); oss < < setw(2) << setfill('0') << hex << (int)(inchar); return oss.str(); } int main() { unsigned char a = 131; std::cout << uchar2hex(a) << std::endl; } 

    Simplemente no es digno de implementar un operador de flujo 🙂

    Hm, parece que reinventé la rueda ayer … Pero bueno, al menos es una rueda genérica esta vez 🙂 Las char están impresas con dos dígitos hexadecimales, s short con 4 dígitos hexadecimales, etc.

     template struct hex_t { T x; }; template hex_t hex(T x) { hex_t h = {x}; return h; } template std::ostream& operator< <(std::ostream& os, hex_t h) { char buffer[2 * sizeof(T)]; for (auto i = sizeof buffer; i--; ) { buffer[i] = "0123456789ABCDEF"[hx & 15]; hx >>= 4; } os.write(buffer, sizeof buffer); return os; } 

    Yo sugeriría:

     std::cout < < setbase(16) << 32; 

    Tomado de: http://www.cprogramming.com/tutorial/iomanip.html

    Puedes probar el siguiente código:

     unsigned char a = 0; unsigned char b = 0xff; cout < < hex << "a is " << int(a) << "; b is " << int(b) << endl; cout << hex << "a is " << setfill('0') << setw(2) << int(a) << "; b is " << setfill('0') << setw(2) << int(b) << endl; cout << hex << uppercase << "a is " << setfill('0') << setw(2) << int(a) << "; b is " << setfill('0') << setw(2) << int(b) << endl; 

    Salida:

    a is 0; b is ff

    a is 00; b is ff

    a is 00; b is FF

    Uso lo siguiente en win32 / linux (32/64 bit):

     #include  #include  template  std::string HexToString(T uval) { std::stringstream ss; ss < < "0x" << std::setw(sizeof(uval) * 2) << std::setfill('0') << std::hex << +uval; return ss.str(); } 

    Me gustaría publicar mi versión de reinvención basada en @ FredOverflow. Hice las siguientes modificaciones.

    fijar:

    • Rhs del operator< < debe ser del tipo de referencia const . En el código de @ FredOverflow, hx >>= 4 cambia la salida h , que sorprendentemente no es compatible con la biblioteca estándar, y el tipo T se considera estructuralmente de copia.
    • Supongamos que solo CHAR_BITS es un múltiplo de 4. El código de @ FredOverflow asume que char es de 8 bits, lo que no siempre es cierto, en algunas implementaciones en DSP, particularmente, no es raro que char sea ​​de 16 bits, 24 bits, 32. bits, etc.

    mejorar:

    • Admite todos los demás manipuladores de biblioteca estándar disponibles para tipos integrales, por ej. std::uppercase . Debido a que la salida de formato se utiliza en _print_byte , los manipuladores de biblioteca estándar todavía están disponibles.
    • Agregue hex_sep para imprimir bytes separados (tenga en cuenta que en C / C ++ un 'byte' es por definición una unidad de almacenamiento con el tamaño de char ). Agregue un parámetro de plantilla Sep e _Hex y _Hex en hex y hex_sep respectivamente.
    • Evite la inflamación del código binario. La función _print_byte se extrae del operator< < , con un size parámetro de función , para evitar la creación de instancias para diferentes Size .

    Más sobre la inflamación del código binario:

    Como se menciona en la mejora 3, no importa qué tan extensamente se usen hex_sep y hex , solo dos copias de la función (casi) duplicada saldrán en el código binario: _print_byte y _print_byte . Y es posible que se dé cuenta de que esta duplicación también se puede eliminar utilizando exactamente el mismo enfoque: agregue un parámetro de función sep . Sí, pero si lo hace, se necesita un tiempo de ejecución if(sep) es necesario. Quiero una utilidad de biblioteca común que se pueda usar extensamente en el progtwig, por lo que me vi comprometido con la duplicación en lugar de con la sobrecarga del tiempo de ejecución. Lo logré usando el tiempo de comstackción if : C ++ 11 std::conditional , la sobrecarga de la llamada a la función puede optimizarse fuera de inline .

    hex_print.h:

     namespace Hex { typedef unsigned char Byte; template  struct _Hex { _Hex(const T& t) : val(t) {} const T& val; }; template  std::ostream& operator< <(std::ostream& os, const _Hex& h); } template  Hex::_Hex hex(const T& x) { return Hex::_Hex(x); } template  Hex::_Hex hex_sep(const T& x) { return Hex::_Hex(x); } #include "misc.tcc" 

    hex_print.tcc:

     namespace Hex { struct Put_space { static inline void run(std::ostream& os) { os < < ' '; } }; struct No_op { static inline void run(std::ostream& os) {} }; #if (CHAR_BIT & 3) // can use C++11 static_assert, but no real advantage here #error "hex print utility need CHAR_BIT to be a multiple of 4" #endif static const size_t width = CHAR_BIT >> 2; template  std::ostream& _print_byte(std::ostream& os, const void* ptr, const size_t size) { using namespace std; auto pbyte = reinterpret_cast(ptr); os < < hex << setfill('0'); for (int i = size; --i >= 0; ) { os < < setw(width) << static_cast(pbyte[i]); conditional::type::run(os); } return os < < setfill(' ') << dec; } template  inline std::ostream& operator< <(std::ostream& os, const _Hex& h) { return _print_byte(os, &h.val, sizeof(T)); } } 

    prueba:

     struct { int x; } output = {0xdeadbeef}; cout < < hex_sep(output) << std::uppercase << hex(output) << endl; 

    salida:

    de ad be ef DEADBEEF

    Me doy cuenta de que esta es una vieja pregunta, pero también es un resultado superior de Google en la búsqueda de una solución a un problema muy similar que tengo, que es el deseo de implementar un entero arbitrario a las conversiones de cadenas hexadecimales dentro de una clase de plantilla. Mi objective final era en realidad una plantilla de subclase Gtk::Entry que permitiera editar varios anchos enteros en hexadecimal, pero eso está al lado del punto.

    Esto combina el operator+ unario operator+ truco con std::make_unsigned de para evitar el problema de la extensión de signo negativo int8_t o los valores de signed char que se produce en esta respuesta

    De todos modos, creo que esto es más sucinto que cualquier otra solución genérica. Debería funcionar para cualquier tipo de entero con signo o sin signo, y arroja un error en tiempo de comstackción si intentas crear una instancia de la función con cualquier tipo no entero.

     template < typename T, typename = typename std::enable_if::value, T>::type > std::string toHexString(const T v) { std::ostringstream oss; oss < < std::hex << +((typename std::make_unsigned::type)v); return oss.str(); } 

    Algunos ejemplos de uso:

     int main(int argc, char**argv) { int16_t val; // Prints 'ff' instead of "ffffffff". Unlike the other answer using the '+' // operator to extend sizeof(char) int types to int/unsigned int std::cout < < toHexString(int8_t(-1)) << std::endl; // Works with any integer type std::cout << toHexString(int16_t(0xCAFE)) << std::endl; // You can use setw and setfill with strings too -OR- // the toHexString could easily have parameters added to do that. std::cout << std::setw(8) << std::setfill('0') << toHexString(int(100)) << std::endl; return 0; } 

    Actualización: Alternativamente, si no te gusta la idea de que ostringstream esté utilizando, puedes combinar el truco del operador de plantillas y unarios con la solución basada en estructuras de la respuesta aceptada para lo siguiente. Tenga en cuenta que aquí, modifiqué la plantilla eliminando la comprobación de los tipos enteros. El uso de make_unsigned podría ser suficiente para las garantías de seguridad de tipo de tiempo de comstackción.

     template  struct HexValue { T value; HexValue(T _v) : value(_v) { } }; template  inline std::ostream& operator< <(std::ostream& o, const HexValue& hs) { return o < < std::hex << +((typename std::make_unsigned::type) hs.value); } template  const HexValue toHex(const T val) { return HexValue(val); } // Usage: std::cout < < toHex(int8_t(-1)) << std::endl; 

    Bueno, esto funciona para mí:

     std::cout < < std::hex << (0xFF & a) << std::endl; 

    Si acaba de lanzar (int) como se sugiere, podría agregar 1s a la izquierda de a si su bit más significativo es 1. Entonces hacer esta operación AND binaria garantiza que la salida tendrá los bits izquierdos llenos por 0 y también los convertirá a unsigned int forzando a cout a imprimirlo como hex.

    Espero que esto ayude.

    Esto también funcionará:

     std::ostream& operator< < (std::ostream& o, unsigned char c) { return o<<(int)c; } int main() { unsigned char a = 06; unsigned char b = 0xff; std::cout << "a is " << std::hex << a <<"; b is " << std::hex << b << std::endl; return 0; } 

    Lo he usado de esta manera.

      char strInput[] = "yourchardata"; char chHex[2] = ""; int nLength = strlen(strInput); char* chResut = new char[(nLength*2) + 1]; memset(chResut, 0, (nLength*2) + 1); for (int i = 0; i < nLength; i++) { sprintf(chHex, "%02X", strInput[i]& 0x00FF); memcpy(&(chResut[i*2]), chHex, 2); } printf("\n%s",chResut); delete chResut; chResut = NULL;