Frage

Ich möchte die Arbeit mit nicht signierten 8-bit-Variablen in C++.Entweder unsigned char oder uint8_t den trick tun, so weit als das arithmetische betroffen ist (was zu erwarten ist, da AFAIK uint8_t ist nur ein alias für unsigned char, oder, damit der debugger zeigt es.

Das problem ist, dass, wenn ich ausdrucken der Variablen mit ostream in C++ behandelt es als char.Wenn ich habe:

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

dann wird die Ausgabe ist:

a is ^@; b is 377

statt

a is 0; b is ff

Ich habe versucht, mit uint8_t, aber wie ich bereits erwähnt habe, ist das typedef ' ed zum unsigned char, so ist es nicht dasselbe.Wie kann ich meine drucken Variablen korrekt?

Edit: Ich Tue dies in vielen Orten überall in meinem code.Gibt es eine Möglichkeit, kann ich dies tun ohne casting int jedes mal, wenn ich drucken möchten?

War es hilfreich?

Lösung

Ich würde vorschlagen, mit der folgenden Technik:

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 ist kurz, zu schreiben, hat die gleiche Effizienz wie die ursprüngliche Lösung, und es können Sie wählen, um die "original" - Zeichen ausgegeben.Und es ist typsicher (nicht mit der "bösen" Makros :-))

Andere Tipps

Verwenden:

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

Und wenn Sie wollen, Auffüllen mit führenden Nullen dann:

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

Als wir mit C-style-casts, warum nicht aufs ganze gehen, mit terminal C++ Schlechtigkeit, und verwenden Sie ein makro!

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

Sie können dann sagen

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

Edit: Having said that, MartinStettner die Lösung ist viel schöner!

Sie können mehr über diese auf http://cpp.indi.frih.net/blog/2014/09/tippet-printing-numeric-values-for-chars-and-uint8_t/ und http://cpp.indi.frih.net/blog/2014/08/code-critique-stack-overflow-posters-cant-print-the-numeric-value-of-a-char/.Ich bin nur dieses posting, weil es klar geworden ist, dass der Autor des oben genannten Artikeln nicht beabsichtigt.

Die einfachste und am richtigen Technik zu tun, drucken Sie ein Zeichen als hex ist

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

Die readers digest-version, wie dies funktioniert, ist, dass der unäre operator + erzwingt eine nicht op-Typ-Konvertierung in einen int mit dem richtigen Fehler.So, unsigned char konvertiert nach unsigned int signed char konvertiert int-und eine char konvertiert, um entweder unsigned int oder int abhängig davon, ob char signed oder unsigned auf Ihrer Plattform (es kommt wie ein Schock für viele, dass der char ist spezielle und nicht ausdrücklich als entweder signed oder unsigned).

Der einzige Nachteil dieser Technik ist, dass es möglicherweise nicht offensichtlich, was passiert, ein jemand, die ist nicht vertraut mit es.Ich denke aber, dass es besser ist, verwenden Sie die Technik, die korrekt ist, und andere lehren, über Sie, anstatt etwas zu tun, falsch ist aber immer sofort klar.

Gut, das funktioniert für mich:

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

Wenn Sie nur cast (int) wie vorgeschlagen, könnte es hinzufügen 1s Links a wenn Ihr die meisten significant bit ist 1.So macht diese binäre UND-operation garantiert die Ausgabe der linken bits gefüllt von 0s und auch wandelt es in ein unsigned int zwingen cout drucken, um Sie als hex.

Ich hoffe, das hilft.

Hm, es scheint, dass ich das Rad neu erfunden gestern...Aber hey, zumindest ist es ein generisches Rad der Zeit :) chars sind gedruckt mit zwei hex-Ziffern, shorts mit 4 hex-Ziffern und so weiter.

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

Ich würde es tun, wie MartinStettner, aber fügen Sie eine zusätzliche parameter für die Anzahl der Ziffern:

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

Sie haben also zwei zahlen, die durch Standard aber können set vier, acht, oder was auch immer wenn Sie wollen.

zB.

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

Es mag wie overkill, aber wie Bjarne sagte:"Bibliotheken sollten einfach zu bedienen, nicht leicht zu schreiben".

Ich denke, TrungTN und anon ' s Antwort ist gut, aber MartinStettner die Art und Weise der Umsetzung der hex () - Funktion ist nicht wirklich einfach, und zu dunkel, wenn man bedenkt hex << (int)mychar ist bereits ein workaround.

hier ist meine Lösung zu machen "<<"Bediener einfacher:

#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 ist einfach nicht Wert die Implementierung eines stream-operator :-)

Ich würde vorschlagen:

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

Entnommen aus:http://www.cprogramming.com/tutorial/iomanip.html

Sie können versuchen, den folgenden code:

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;

Ausgabe:

a is 0; b is ff

a is 00; b is ff

a is 00; b is FF

Ich verwende den folgenden 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();
}

Ich möchte nach meinen re-re-erfinden-version basierend auf dem @FredOverflow ist.Ich habe die folgenden änderungen vor.

Update:

  • Rhs des operator<< sollte der const Referenz-Typ.In @FredOverflow code h.x >>= 4 änderungen Ausgabe h,, das ist nicht überraschend kompatibel mit standard-library, und geben Sie T ist requared zu kopieren-constructable.
  • Davon aus, dass nur CHAR_BITS ein Vielfaches von 4 ist.@FredOverflow code übernimmt char 8-bit, das ist nicht immer wahr, in einigen Implementierungen auf DSPs, vor allem, ist es nicht ungewöhnlich, dass char 16-bit, 24-bit, 32-bits, etc.

verbessern:

  • Unterstützung alle anderen standard-Bibliothek Manipulatoren verfügbar für Integrale Typen, z.B. std::uppercase.Da format Ausgang ist verwendet _print_byte, standard-Bibliothek Manipulatoren sind noch verfügbar.
  • Hinzufügen hex_sep drucken separaten bytes (beachten Sie, dass in C/C++ einen 'byte' ist per definition ein Speicher-Gerät mit der Größe char).Fügen Sie einen template-parameter Sep und instanziieren _Hex<T, false> und _Hex<T, true> in hex und hex_sep bzw.
  • Vermeiden binary code aufblähen.Funktion _print_byte extrahiert aus operator<<, mit Funktion parameter size, zu vermeiden , die die Instanziierung für verschiedene Size.

Mehr auf Binärcode von aufblasen:

Wie bereits erwähnt Verbesserung 3, egal wie umfangreich hex und hex_sep wird verwendet, nur zwei Kopien von (fast) dupliziert die Funktion wird beendet im Binär-code: _print_byte<true> und _print_byte<false>.Und könnte man erkannte, dass diese Vervielfältigung kann auch eliminiert werden, mit genau dem gleichen Ansatz:hinzufügen einer Funktion parameter sep.Ja, aber wenn dabei eine Laufzeit if(sep) erforderlich ist.Ich möchte eine gemeinsame Bibliothek Dienstprogramm, das kann umfassend genutzt werden in das Programm, damit ich kompromittiert, die auf die Vervielfältigung eher als Laufzeit-overhead.Ich erreichte dies durch die Verwendung von compile-Zeit if:C++11 std::conditional, der overhead des Funktionsaufrufs können hoffentlich optimiert werden entfernt 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));
}

}

test:

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

Ausgabe:

de ad be ef DEADBEEF

Ich weiß, das ist eine alte Frage ist, aber es ist auch ein top-Google-Ergebnis in der Suche nach einer Lösung für ein sehr ähnliches problem, das ich habe, das ist der Wunsch zu implementieren beliebigen integer to hex string-Konvertierungen innerhalb einer template-Klasse.Mein Ziel war eigentlich ein Gtk::Entry Unterklasse Vorlage, die erlauben würde, die Bearbeitung verschiedener integer breiten in hex, aber das ist neben dem Punkt.

Dies kombiniert die unäre operator+ trick mit std::make_unsigned von <type_traits> um zu verhindern, dass das problem von Zeichen-Erweiterung negativ int8_t oder signed char Werte, die Auftritt, in diese Antwort

Wie auch immer, ich glaube, das ist kürzer als jede andere generische Lösung.Es sollte Arbeit für alle signed oder unsigned integer-Typen, und wirft einen Kompilierungsfehler, wenn Sie versuchen, Sie zu instanziieren, die die Funktion für alle nicht-integer-Typen.

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

Einige Beispiele:

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

Update: Alternativ, wenn Sie nicht wie die Idee der ostringstream verwendet, Sie können kombinieren die Template-und unärer operator trick mit der akzeptierten Antwort, struct-basierte Lösung für die folgenden.Beachten Sie, dass hier, modifizierte ich die Vorlage durch entfernen des Hakens für integer-Typen.Die make_unsigned usage könnte genug für compile time type safety garantiert.

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;

Dies funktioniert auch:

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

Ich habe in dieser Weise verwendet.

    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;
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top