come posso stampare un carattere non firmato come esadecimale in c ++ usando ostream?

Voglio lavorare con variabili a 8 bit senza segno in C ++. Sia il unsigned char che uint8_t fanno il trucco per quanto riguarda l’aritmetica (il che è previsto, dal momento che AFAIK uint8_t è solo un alias per il unsigned char , o così il debugger lo presenta.

Il problema è che se stampo le variabili usando ostream in C ++ lo tratta come char. Se ho:

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

quindi l’output è:

 a is ^@; b is 377 

invece di

 a is 0; b is ff 

Ho provato a usare uint8_t , ma come ho detto prima, questo è tipizzato con unsigned char , quindi fa lo stesso. Come posso stampare correttamente le mie variabili?

Modifica: lo faccio in molti punti del mio codice. C’è un modo in cui posso farlo senza trasmettere a int ogni volta che voglio stampare?

    Suggerirei di utilizzare la seguente tecnica:

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

    È breve da scrivere, ha la stessa efficienza della soluzione originale e ti consente di scegliere di utilizzare l'output di carattere "originale". Ed è sicuro dal tipo (non usando macro "cattive" :-))

    Uso:

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

    E se vuoi riempire gli zeri iniziali allora:

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

    Dato che stiamo usando cast in stile C, perché non andare tutto il maiale con il malus del terminale C ++ e usare una macro!

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

    puoi quindi dire

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

    Edit: Detto questo, la soluzione di MartinStettner è molto più bella!

    Puoi leggere ulteriori informazioni al riguardo su http://cpp.indi.frih.net/blog/2014/09/tippet-printing-numeric-values-for-chars-and-uint8_t/ e http: //cpp.indi. frih.net/blog/2014/08/code-critique-stack-overflow-posters-cant-print-the-numeric-value-of-a-char/ . Sto solo postando questo perché è diventato chiaro che l’autore degli articoli di cui sopra non ha intenzione di farlo.

    La tecnica più semplice e corretta per stampare un carattere come esadecimale

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

    I lettori digeriscono la versione di come funziona che l'operatore unario + impone una conversione di tipo non operativo a un int con la firma corretta. Quindi, un char non firmato viene convertito in unsigned, un char firmato viene convertito in int e un char viene convertito in unsigned o int unsigned a seconda che il char sia firmato o non firmato sulla piattaforma (ciò rappresenta uno shock per molti che char è speciale e non specificato come firmato o non firmato).

    L'unico aspetto negativo di questa tecnica è che potrebbe non essere evidente ciò che sta accadendo a qualcuno che non ha familiarità con esso. Tuttavia, penso che sia meglio usare la tecnica che è corretta e insegnare ad altri su di esso piuttosto che fare qualcosa che non è corretto, ma più immediatamente chiaro.

    Lo farei come MartinStettner, ma aggiungo un parametro aggiuntivo per il numero di cifre:

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

    Quindi hai due cifre di default ma puoi impostare quattro, otto o qualsiasi altra cosa se vuoi.

    per esempio.

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

    Può sembrare eccessivo, ma come ha detto Bjarne: "le biblioteche dovrebbero essere facili da usare, non facili da scrivere".

    Penso che la risposta di TrungTN e di anon sia ok, ma il modo di MartinStettner di implementare la funzione hex () non è molto semplice, e troppo scuro, considerando l’hex < < (int) mychar è già una soluzione.

    ecco la mia soluzione per rendere più semplice l’operatore “< <":

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

    Non è semplicemente degno implementare un operatore di streaming 🙂

    Hm, sembra che abbia re-inventato la ruota ieri … Ma hey, almeno questa volta è una ruota generica 🙂 I char vengono stampati con due cifre esadecimali, short s con 4 cifre esadecimali e così via.

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

    Io suggerirei:

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

    Tratto da: http://www.cprogramming.com/tutorial/iomanip.html

    Puoi provare il seguente codice:

     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; 

    Produzione:

    a is 0; b is ff

    a is 00; b is ff

    a is 00; b is FF

    Io uso il seguente su 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(); } 

    Vorrei pubblicare la mia versione di re-reinvenzione basata su @ FredOverflow. Ho fatto le seguenti modifiche.

    risolvere:

    • Rhs operator< < dovrebbe essere di tipo const reference. Nel codice di @ FredOverflow, hx >>= 4 cambia l'output h , che è sorprendentemente non compatibile con la libreria standard e il tipo T è richiesto per essere costruibile con la copia.
    • Supponiamo che solo CHAR_BITS sia un multiplo di 4. @ Il codice di FredOverflow presuppone che char sia 8 bit, il che non è sempre vero, in alcune implementazioni su DSP, in particolare, non è raro che char sia a 16 bit, 24 bit, 32- bit, ecc.

    Migliorare:

    • Supporta tutti gli altri manipolatori di libreria standard disponibili per i tipi interi, ad esempio std::uppercase . Poiché l'output di formato viene utilizzato in _print_byte , i manipolatori di libreria standard sono ancora disponibili.
    • Aggiungi hex_sep per stampare byte separati (nota che in C / C ++ un 'byte' è per definizione un'unità di memoria con le dimensioni di char ). Aggiungi un parametro template Sep e istanziato _Hex e _Hex in hex e hex_sep rispettivamente.
    • Evita il codice binario. La funzione _print_byte viene estratta operator< < , con una size parametro della funzione , per evitare l'istanziazione per Size diverse.

    Maggiori informazioni sul codice binario:

    Come menzionato nel miglioramento 3, non importa quanto estensivamente siano usati hex e hex_sep , solo due copie della funzione (quasi) duplicata usciranno nel codice binario: _print_byte e _print_byte . E potresti capire che questa duplicazione può anche essere eliminata usando esattamente lo stesso approccio: aggiungi un parametro funzione sep . Sì, ma se lo fa, è necessario un runtime if(sep) . Voglio un'utility di libreria comune che possa essere utilizzata estesamente nel programma, quindi ho compromesso la duplicazione piuttosto che il sovraccarico di runtime. Ho ottenuto questo risultato utilizzando la fase di compilazione if : C ++ 11 std::conditional , il sovraccarico della chiamata alla funzione può essere ottimizzato via via in 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)); } } 

    test:

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

    produzione:

    de ad be ef DEADBEEF

    Mi rendo conto che questa è una vecchia domanda, ma è anche un risultato di primo livello nella ricerca di una soluzione ad un problema molto simile, che è il desiderio di implementare un intero arbitrario per le conversioni di stringhe esadecimali all’interno di una class template. Il mio objective finale era in realtà un modello sottoclass Gtk::Entry che permettesse di modificare varie larghezze intere in hex, ma questo è oltre il punto.

    Questo combina l’ operator+ unario operator+ trucco con std::make_unsigned da per prevenire il problema dell’estensione negativa del segno int8_t o dei valori signed char che si verificano in questa risposta

    Ad ogni modo, credo che questo sia più succinto di qualsiasi altra soluzione generica. Dovrebbe funzionare per qualsiasi tipo di intero con segno o senza segno e genera un errore in fase di compilazione se si tenta di creare un’istanza della funzione con qualsiasi tipo non intero.

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

    Alcuni esempi di utilizzo:

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

    Aggiornamento: In alternativa, se non ti piace l'idea del ostringstream in uso, puoi combinare il trucco dell'operatore di template e unario con la soluzione strutturata della risposta accettata per quanto segue. Nota che qui ho modificato il modello rimuovendo il controllo per i tipi di interi. L'utilizzo di make_unsigned potrebbe essere sufficiente per garantire la sicurezza del tipo a tempo compilato.

     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; 

    Bene, questo funziona per me:

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

    Se hai appena lanciato (int) come suggerito, potrebbe aggiungere 1 s alla sinistra di a se il suo bit più significativo è 1. Quindi, eseguendo questa operazione AND binaria, l'output avrà i bit di sinistra pieni di 0 e lo converte anche in unsigned int costringendo Cout a stamparlo come esadecimale.

    Spero che aiuti.

    Questo funzionerà anche:

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

    Ho usato in questo modo.

      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;