Pregunta

Quiero trabajar con variables de 8 bits sin firmar en C++.Cualquiera unsigned char o uint8_t hacer el truco en lo que respecta a la aritmética (lo cual es de esperar, ya que AFAIK uint8_t es solo un alias para unsigned char, o eso es lo que presenta el depurador.

El problema es que si imprimo las variables usando ostream en C++, las 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 está definido como unsigned char, entonces 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 manera de que pueda hacer esto? sin casting a int cada vez que quiero imprimir?

¿Fue útil?

Solución

Se recomienda 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 que le permite elegir utilizar la salida "original" carácter. Y es de tipo seguro (no usar macros "malos": -))

Otros consejos

Uso:

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

Y si quieres rellenando con ceros a la izquierda, a continuación:

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

Como estamos usando C-estilo arroja, por qué no ir hasta el final con la maldad terminal de C ++ y utilizar una macro!

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

A continuación, se puede decir

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

Editar Una vez dicho esto, la solución de MartinStettner es mucho más agradable

!

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/ . Sólo estoy fijando esto, ya que ha quedado claro que el autor de los artículos anteriores no se propone.

La técnica más sencilla y correcta de hacerlo imprimir un char que es hexagonal

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

Los lectores digieren versión de cómo funciona esto es que el operador unario + obliga a una conversión de ningún tipo op a un int con el signo numérico correcto. Por lo tanto, un unsigned char convierte a unsigned int, char firmado convierte a int, y un char convierte a cualquiera unsigned int o INT dependiendo de si Char está firmada o no en su plataforma (viene como una sorpresa para muchos que char es especial y no se especifica ya sea con o sin signo).

El único aspecto negativo de esta técnica es que puede que no sea evidente lo que está sucediendo a un alguien que no está familiarizado con ella. Sin embargo, creo que es mejor utilizar la técnica que es correcto y enseñar a otros acerca de él en lugar de hacer algo que es incorrecto pero más claro de inmediato.

Bueno, esto funciona para mí:

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

Si sólo echas (int) como sugirió que podría añadir 1s a la izquierda de a si su bit más significativo es 1. Por lo tanto hacer esta operación binaria Y garantiza la salida tendrá los bits de izquierda ocupados por 0s y también lo convierte a unsigned int forzando cout imprimirlo como hex.

Espero que esto ayude.

Hm, parece que reinventado la rueda de ayer ... Pero bueno, al menos es una rueda genérico de este tiempo :) char s se imprimen con dos dígitos hexadecimales, short s con 4 dígitos hexadecimales y así sucesivamente.

template<typename T>
struct hex_t
{
    T x;
};

template<typename T>
hex_t<T> hex(T x)
{
    hex_t<T> h = {x};
    return h;
}

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

lo haría como MartinStettner además de añadir un parámetro adicional para el número 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

Así que hay dos dígitos por defecto, pero puede configurar cuatro, ocho, o lo que sea, si usted quiere.

por ejemplo.

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

Puede parecer una exageración, pero como Bjarne dijo:. "Las bibliotecas deben ser fáciles de usar, no es fácil de escribir"

Creo TrungTN y de anon respuesta es aceptable, pero forma de implementar el hexágono () no es realmente simple, y demasiado oscura, teniendo en cuenta hexagonal << mychar (int) es ya una solución. De MartinStettner

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

#include <sstream>
#include <iomanip>

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

Es que no es digno de la implementación de un operador de corriente: -)

Yo sugeriría:

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

De: http://www.cprogramming.com/tutorial/iomanip.html

Puede 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

utilizo el siguiente en Win32 / Linux (32/64 bits):

#include <iostream>
#include <iomanip>

template <typename T>
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 reinventada basada en la de @FredOverflow.Hice las siguientes modificaciones.

arreglar:

  • Rhs de operator<< debería ser de const tipo de referencia.En el código de @FredOverflow, h.x >>= 4 cambia la salida h, que sorprendentemente no es compatible con la biblioteca estándar y escribe T Se requiere que se pueda copiar y construir.
  • Suponer sólo CHAR_BITS es múltiplo de 4.El código de @FredOverflow supone char es de 8 bits, lo que no siempre es cierto; en algunas implementaciones en DSP, en particular, no es raro que char es de 16 bits, 24 bits, 32 bits, etc.

mejorar:

  • Admite todos los demás manipuladores de biblioteca estándar disponibles para tipos integrales, p. std::uppercase.Debido a que la salida en formato se utiliza en _print_byte, los manipuladores de biblioteca estándar todavía están disponibles.
  • Agregar 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).Agregar un parámetro de plantilla Sep y crear una instancia _Hex<T, false> y _Hex<T, true> en hex y hex_sep respectivamente.
  • Evite la hinchazón del código binario.Función _print_byte se extrae de operator<<, con un parámetro de función size, para evitar la creación de instancias para diferentes Size.

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

Como se mencionó en la mejora 3, no importa cuán extensamente hex y hex_sep se utiliza, sólo dos copias de la función (casi) duplicada saldrán en código binario: _print_byte<true> y _print_byte<false>.Y quizás te hayas dado cuenta de que esta duplicación también se puede eliminar utilizando exactamente el mismo enfoque:agregar un parámetro de función sep.Sí, pero si lo hace, un tiempo de ejecución if(sep) es necesario.Quiero una utilidad de biblioteca común que pueda usarse ampliamente en el programa, por lo que comprometí la duplicación en lugar de la sobrecarga del tiempo de ejecución.Logré esto usando tiempo de compilación. if:C++11 std::conditional, es de esperar que la sobrecarga de la llamada a la función se pueda optimizar mediante inline.

hex_print.h:

namespace Hex
{
typedef unsigned char Byte;

template <typename T, bool Sep> struct _Hex
{
    _Hex(const T& t) : val(t)
    {}
    const T& val;
};

template <typename T, bool Sep>
std::ostream& operator<<(std::ostream& os, const _Hex<T, Sep>& h);
}

template <typename T>  Hex::_Hex<T, false> hex(const T& x)
{ return Hex::_Hex<T, false>(x); }

template <typename T>  Hex::_Hex<T, true> hex_sep(const T& x)
{ return Hex::_Hex<T, true>(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 <bool Sep>
std::ostream& _print_byte(std::ostream& os, const void* ptr, const size_t size)
{
    using namespace std;

    auto pbyte = reinterpret_cast<const Byte*>(ptr);

    os << hex << setfill('0');
    for (int i = size; --i >= 0; )
    {
        os << setw(width) << static_cast<short>(pbyte[i]);
        conditional<Sep, Put_space, No_op>::type::run(os);
    }
    return os << setfill(' ') << dec;
}

template <typename T, bool Sep>
inline std::ostream& operator<<(std::ostream& os, const _Hex<T, Sep>& h)
{
    return _print_byte<Sep>(os, &h.val, sizeof(T));
}

}

prueba:

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

producción:

de ad be ef DEADBEEF

Me di cuenta que es una vieja pregunta, pero también es un resultado superior Google en la búsqueda de una solución a un problema muy similar que tengo, que es el deseo de implementar entero arbitrario para la conversión de series hexagonal dentro de una clase de plantilla. Mi objetivo final era en realidad una plantilla Gtk::Entry subclase que permitiría la edición de varios anchos enteros en hexadecimal, pero eso no viene al caso.

Esto combina el truco unario operator+ con std::make_unsigned de <type_traits> para evitar el problema de la int8_t o signed char valores negativos de signo extiende que se produce en esta respuesta

De todos modos, creo que esto es más breve que cualquier otra solución genérica. Se debe trabajar para cualquier Signed o tipos de enteros sin signo, y lanza un error de compilación si se intenta crear una instancia de la función con cualquier tipo no enteros.

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

Algunos Uso de ejemplo:

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: Como alternativa, si no te gusta la idea de la ostringstream siendo utilizado, puede combinar la plantilla y el truco operador unitario con una solución basada en la estructura de la respuesta aceptada para el siguiente . Tenga en cuenta que aquí, he modificado la plantilla mediante la eliminación de la comprobación de tipos enteros. El uso de make_unsigned podría ser suficiente para las garantías de seguridad de tipo en tiempo de compilación.

template <typename T>
struct HexValue 
{
  T value;
  HexValue(T _v) : value(_v) { }
};

template <typename T>
inline std::ostream& operator<<(std::ostream& o, const HexValue<T>& hs)
{
  return o << std::hex << +((typename std::make_unsigned<T>::type) hs.value);
}

template <typename T>
const HexValue<T> toHex(const T val)
{
  return HexValue<T>(val);
}

// Usage:
std::cout << toHex(int8_t(-1)) << std::endl;

Esto también funciona:

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

He utilizado 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;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top