Domanda

Voglio lavorare con le variabili a 8 bit senza segno in C ++. Sia unsigned char o uint8_t fare il trucco per quanto riguarda l'aritmetica è interessato (che si prevede, dal momento che per quanto ne so int è solo un alias per <=>, o giù di lì il debugger lo presenta.

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

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

allora l'uscita è:

a is ^@; b is 377

anziché

a is 0; b is ff

Ho provato ad utilizzare <=>, ma come ho detto prima, questo è typedef'ed a <=>, in modo che lo stesso. Come posso stampare le mie variabili correttamente?

Modifica Lo faccio in molti luoghi in tutto il mio codice. C'è un modo che io possa fare questo senza fusione per <=> ogni volta che voglio stampare?

È stato utile?

Soluzione

Io suggerirei di usare 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;
}

E 'breve per scrivere, ha la stessa efficienza come la soluzione originale e consente di scegliere se utilizzare l'uscita personaggio "originale". Ed è type-safe (se non utilizzano le macro "male": -))

Altri suggerimenti

Usa:

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

E se si vuole imbottitura con zeri allora:

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

Come stiamo usando C-style cast, perché non andare fino in fondo con il terminale C ++ cattiveria e utilizzare una macro!

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

si può quindi dire che

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

Modifica Detto questo, la soluzione di MartinStettner è molto più bello

!

Si può leggere di più su questo a 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/ . Io sto solo postando questo perché è diventato evidente che l'autore degli articoli di cui sopra non intende.

La tecnica più semplice e la più corretta da fare stampare un char 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 digerire versione di come funziona è che l'operatore unario + costringe una conversione di nessun tipo op ad un int con il signedness corretta. Così, un unsigned char converte in unsigned int, un char firmato converte a int, e un char converte in uno unsigned int o int a seconda che char è firmato o non firmato sulla vostra piattaforma (si tratta come uno shock per molti che char è speciale e non specificati come con o senza segno).

L'unica nota negativa di questa tecnica è che può non essere evidente ciò che sta accadendo a un qualcuno che non ha familiarità con esso. Tuttavia, penso che sia meglio usare la tecnica che sia corretto e insegnare agli altri su di esso piuttosto che fare qualcosa che non è corretto, ma più immediatamente evidente.

Bene, questo funziona per me:

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

Se hai appena lanci (int) come suggerito potrebbe aggiungere 1s a sinistra del a se bit più significativo è 1. Così facendo di questo binario AND garantisce l'uscita avrà i bit di sinistra riempito da 0 e anche converte unsigned int costringendo cout stamparlo come esadecimale.

Spero che questo aiuta.

Hm, sembra che io reinventato la ruota di ieri ... Ma hey, almeno è una ruota generica questa volta :) char s sono stampati con due cifre esadecimali, short s con 4 cifre esadecimali e così via.

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 farei come MartinStettner ma aggiungo un parametro in più per 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

In modo da avere due cifre per impostazione predefinita, ma è possibile impostare quattro, otto, o qualsiasi altra cosa se si vuole.

ad es.

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

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

Credo TrungTN e anon di risposta è a posto, ma il modo di attuare l'esagono () non è molto semplice, e troppo scuro, considerando esagonale << (int) MyChar è già una soluzione. Di MartinStettner

Questa è la mia soluzione per rendere "<<" operatore facile:

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

E 'solo che non merita l'attuazione di un operatore di flusso: -)

Vorrei suggerire:

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

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

È possibile 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;

Output:

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

Mi piacerebbe pubblicare la mia versione re-re-inventare sulla base di @ FredOverflow di. Ho fatto le seguenti modifiche.

fix:

  • Rhs di operator<< dovrebbe essere di const tipo di riferimento. In @ di FredOverflow codice, h.x >>= 4 uscita cambia h, che è sorprendentemente non è compatibile con libreria standard, e digitare T è requared essere copia-costruibile.
  • assumere solo CHAR_BITS è un multiplo di 4. @ codice di FredOverflow assume char è di 8 bit, che non è sempre vero, in alcune implementazioni di DSP, in particolare, non è raro che std::uppercase è 16 -bits, 24-bit, 32-bit, ecc.

migliorare:

  • Supporto tutti gli altri manipolatori della libreria standard disponibili per i tipi integrali, per esempio _print_byte. Dato che l'output formato viene utilizzato in hex_sep, manipolatori della libreria standard sono ancora disponibili.
  • Aggiungi Sep stampare byte separati (si noti che in C / C ++ di un 'byte' è per definizione un'unità di memorizzazione con le dimensioni di _Hex<T, false>). Aggiungere un parametro di modello _Hex<T, true> e istanziare hex e size in Size e _print_byte<true> rispettivamente.
  • Evitare di codice binario gonfiare. Funzione _print_byte<false> viene estratto fuori sep, con parametro funzionale if(sep), per evitare istanziazione per diverso if.

Ulteriori informazioni su gonfiare codice binario:

Come menzionato in miglioramento 3, per quanto ampiamente std::conditional e inline viene utilizzato, solo due copie di (quasi) duplicati funzione uscite in codice binario: de ad be ef DEADBEEF e <=>. E si potrebbe capito che questa duplicazione può anche essere eliminato utilizzando esattamente lo stesso approccio: aggiungere un parametro di funzione <=>. Sì, ma se così facendo, è necessario un tempo di esecuzione <=>. Voglio un programma di utilità libreria comune che può essere ampiamente utilizzato nel programma, quindi ho compromesso sulla duplicazione piuttosto che in testa runtime. Ho raggiunto questo utilizzando fase di compilazione <=>:. C ++ 11 <=>, l'overhead di chiamata di funzione può essere ottimizzato auspicabilmente distanza da <=>

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

}

Test:

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

uscita:

<=>

Mi rendo conto che è una vecchia questione, ma è anche un buon risultato di Google nella ricerca di una soluzione ad un problema molto simile che ho, che è il desiderio di implementare intero arbitrario alle conversioni stringa esadecimale all'interno di una classe template. Il mio obiettivo finale è stato in realtà un modello Gtk::Entry sottoclasse che permetterebbe l'editing varie larghezze interi in esadecimale, ma non è questo il punto.

Questo combina la operator+ trucco unario con std::make_unsigned da <type_traits> per evitare il problema di int8_t o signed char valori negativi del segno-in estensione che si verifica in questa risposta

In ogni caso, credo che questo è più succinta rispetto a qualsiasi altra soluzione generica. Dovrebbe funzionare per qualsiasi tipi interi senza segno firmato o, e lancia un errore di compilazione se si tenta di creare un'istanza della funzione con qualsiasi tipo non interi.

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

Qualche esempio 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 della ostringstream in uso, è possibile combinare il template e unario operatore trucco con la soluzione struct basate sulla risposta accettata per i seguenti . Si noti che qui, ho modificato il modello rimuovendo il controllo per tipi interi. Il make_unsigned utilizzo potrebbe essere sufficiente per le garanzie di sicurezza di tipo fase di compilazione.

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;

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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top