Ich möchte mit vorzeichenlosen 8-Bit-Variablen in C ++ arbeiten. Entweder unsigned char
oder uint8_t
mache den Trick, was die Arithmetik betrifft (was erwartet wird, da AFAIK uint8_t
nur ein Alias für ist unsigned char
, oder so präsentiert es der Debugger.
Das Problem ist, dass wenn ich die Variablen mit ostream in C ++ drucke, sie als Zeichen behandelt werden. Wenn ich habe:
unsigned char a = 0;
unsigned char b = 0xff;
cout << "a is " << hex << a <<"; b is " << hex << b << endl;
dann ist die Ausgabe:
a is ^@; b is 377
anstatt
a is 0; b is ff
Ich habe es versucht uint8_t
, aber wie ich bereits erwähnt habe, ist das typisiert unsigned char
, also macht es dasselbe. Wie kann ich meine Variablen richtig drucken?
Bearbeiten: Ich mache dies an vielen Stellen in meinem Code. Gibt es eine Möglichkeit, dies zu tun, ohneint
jedes Mal zu gießen, wenn ich drucken möchte?
c++
formatting
ostream
Nathan Fellman
quelle
quelle
Antworten:
Ich würde die folgende Technik vorschlagen:
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 ermöglicht es Ihnen, die "ursprüngliche" Zeichenausgabe zu verwenden. Und es ist typsicher (ohne "böse" Makros :-))
quelle
(int)hs.c
als schreibenstatic_cast<int>(hs.c)
? : Punsigned char
das Problem behoben.operator<<
Gesagte den Modus des angegebenen Streams auf hexadezimal ändert:cout << hex(a) << 100
Sie werden überrascht sein. Sie sollten den Status des Streams speichern, bevor Sie ihn ändern, und ihn später wiederherstellen.char
in Hex ist.Verwenden:
cout << "a is " << hex << (int) a <<"; b is " << hex << (int) b << endl;
Und wenn Sie mit führenden Nullen auffüllen möchten, dann:
#include <iomanip> ... cout << "a is " << setw(2) << setfill('0') << hex << (int) a ;
Da wir Casts im C-Stil verwenden, sollten Sie das ganze Problem mit der C ++ - Schlechtigkeit des Terminals lösen und ein Makro verwenden!
#define HEX( x ) setw(2) << setfill('0') << hex << (int)( x )
du kannst dann sagen
cout << "a is " << HEX( a );
Edit: Trotzdem ist die Lösung von MartinStettner viel schöner!
quelle
Weitere Informationen hierzu finden Sie unter 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 poste dies nur, weil klar geworden ist, dass der Autor der oben genannten Artikel dies nicht beabsichtigt.
Die einfachste und korrekteste Technik, um ein Zeichen als Hex zu drucken, 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 Digest-Version des Lesers zeigt, dass der Operator unary + eine Konvertierung vom Typ no op in ein int mit der richtigen Signatur erzwingt. Ein vorzeichenloses Zeichen wird in vorzeichenloses int konvertiert, ein vorzeichenbehaftetes Zeichen wird in int konvertiert und ein Zeichen wird entweder in vorzeichenloses int oder int konvertiert, je nachdem, ob char auf Ihrer Plattform signiert oder nicht signiert ist (für viele ist es ein Schock, dass char etwas Besonderes ist und nicht als signiert oder nicht signiert angegeben).
Das einzig Negative dieser Technik ist, dass es möglicherweise nicht offensichtlich ist, was mit jemandem passiert, der mit ihr nicht vertraut ist. Ich denke jedoch, dass es besser ist, die richtige Technik zu verwenden und andere darüber zu unterrichten, als etwas zu tun, das falsch, aber sofort klarer ist.
quelle
unsigned int
/int
sind. Dies bedeutet, dass für Zeichen mit negativem Vorzeichen (oder beispielsweise int16_t) 8 Halbbytes ausgegeben werden, von denen die ersten 6 sindF
.(+c & 0xFF)
.+
ist unnötig, die Binärdatei&
konvertiert bereits in einint
.Nun, das funktioniert bei mir:
std::cout << std::hex << (0xFF & a) << std::endl;
Wenn Sie nur
(int)
wie vorgeschlagena
umwandeln , wird möglicherweise 1s links von 1 hinzugefügt, wenn das höchstwertige Bit 1 ist. Wenn Sie also diese binäre UND-Operation ausführen, wird die Ausgabe garantiert, dass die linken Bits mit 0s gefüllt sind, und konvertiert sie auch in vorzeichenloses int, wodurch cout zum Drucken gezwungen wird es als hex.Ich hoffe das hilft.
quelle
Hm, anscheinend habe ich das Rad gestern neu erfunden ... Aber hey, zumindest ist es diesmal ein generisches Rad :)
char
s werden mit zwei hexadezimalen Ziffern gedruckt,short
s mit 4 hexadezimalen 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; }
quelle
std::uppercase
undstd::nouppercase
Manipulatoren (die diestd::ios_base::flags::uppercase
iosflag manipulieren )Ich würde es wie MartinStettner machen, aber einen zusätzlichen Parameter für die Anzahl der Ziffern hinzufügen:
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 standardmäßig zwei Ziffern, können aber vier, acht oder was auch immer einstellen, wenn Sie möchten.
z.B.
int main() { short a = 3142; std:cout << hex(a,4) << std::endl; }
Es mag übertrieben erscheinen, aber wie Bjarne sagte: "Bibliotheken sollten einfach zu bedienen und nicht einfach zu schreiben sein".
quelle
Ich denke, die Antwort von TrungTN und anon ist in Ordnung, aber MartinStettners Methode zur Implementierung der hex () - Funktion ist nicht wirklich einfach und zu dunkel, wenn man bedenkt, dass hex << (int) mychar bereits eine Problemumgehung ist.
Hier ist meine Lösung, um den Operator "<<" zu vereinfachen:
#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 lohnt sich einfach nicht, einen Stream-Operator zu implementieren :-)
quelle
Ich benutze folgendes unter 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(); }
quelle
Ich würde vorschlagen:
std::cout << setbase(16) << 32;
Entnommen aus: http://www.cprogramming.com/tutorial/iomanip.html
quelle
Sie können den folgenden Code ausprobieren:
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
quelle
int
jedem Zeitpunkt, zu dem ich dies tun möchte, umwandeln zu müssen, da dies im Code zu oft vorkommt.Ich möchte meine neu erfundene Version basierend auf @ FredOverflow's veröffentlichen. Ich habe die folgenden Änderungen vorgenommen.
Fix:
operator<<
sollte vomconst
Referenztyp sein. Im Code von @ FredOverflow wird dieh.x >>= 4
Ausgabe geänderth
, die überraschenderweise nicht mit der Standardbibliothek kompatibel ist, und der Typ mussT
kopierkonstruierbar sein.CHAR_BITS
ein Vielfaches von 4. @ FredOverflows Code geht vonchar
8 Bit aus, was bei einigen Implementierungen auf DSPs nicht immer der Fall ist. Insbesondere ist es nicht ungewöhnlich, dasschar
es sich um 16 Bit, 24 Bit, 32 Bit usw. Handelt .verbessern:
std::uppercase
. Da die Formatausgabe in verwendet wird_print_byte
, sind weiterhin Standardbibliotheksmanipulatoren verfügbar.hex_sep
, um separate Bytes zu drucken (beachten Sie, dass in C / C ++ ein 'Byte' per Definition eine Speichereinheit mit der Größe von istchar
). Fügen Sie einen Vorlagenparameter hinzuSep
und instanziieren Sie_Hex<T, false>
bzw._Hex<T, true>
inhex
undhex_sep
._print_byte
wirdoperator<<
mit einem Funktionsparameter aus extrahiertsize
, um eine Instanziierung für verschiedene zu vermeidenSize
.Mehr zum Aufblähen von Binärcode:
Wie in Verbesserung 3 erwähnt, werden unabhängig vom Umfang
hex
und derhex_sep
Verwendung nur zwei Kopien der (fast) duplizierten Funktion im Binärcode beendet:_print_byte<true>
und_print_byte<false>
. Und Sie haben vielleicht festgestellt, dass diese Duplizierung auch mit genau demselben Ansatz beseitigt werden kann: Fügen Sie einen Funktionsparameter hinzusep
. Ja, aber wenn diesif(sep)
erforderlich ist , wird eine Laufzeit benötigt. Ich möchte ein allgemeines Bibliotheksdienstprogramm, das häufig im Programm verwendet wird. Daher habe ich bei der Duplizierung Kompromisse eingegangen und nicht den Laufzeitaufwand. Ich habe dies durch die Verwendung der Kompilierungszeit erreichtif
: C ++ 11std::conditional
, der Overhead des Funktionsaufrufs kann hoffentlich durch optimiert werdeninline
.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)); } }
Prüfung:
struct { int x; } output = {0xdeadbeef}; cout << hex_sep(output) << std::uppercase << hex(output) << endl;
Ausgabe:
de ad be ef DEADBEEF
quelle
Mir ist klar, dass dies eine alte Frage ist, aber es ist auch ein Top-Ergebnis von Google bei der Suche nach einer Lösung für ein sehr ähnliches Problem, das ich habe, nämlich den Wunsch, willkürliche Konvertierungen von Ganzzahlen in Hex-Zeichenfolgen innerhalb einer Vorlagenklasse zu implementieren. Mein Endziel war eigentlich eine
Gtk::Entry
Unterklassenvorlage, mit der verschiedene ganzzahlige Breiten in hexadezimaler Form bearbeitet werden können, aber das ist nebensächlich.Dies kombiniert den unären
operator+
Trick mitstd::make_unsigned
von<type_traits>
, um das Problem des vorzeichenverlängernden Negativsint8_t
odersigned char
der in dieser Antwort auftretenden Werte zu vermeidenJedenfalls glaube ich, dass dies prägnanter ist als jede andere generische Lösung. Es sollte für alle vorzeichenbehafteten oder vorzeichenlosen Ganzzahltypen funktionieren und einen Fehler beim Kompilieren auslösen, wenn Sie versuchen, die Funktion mit Nicht-Ganzzahltypen zu instanziieren.
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 Anwendungsbeispiele:
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: Wenn Ihnen die Idee der
ostringstream
Verwendung nicht gefällt, können Sie alternativ den Vorlagen- und den unären Operator-Trick mit der strukturbasierten Lösung der akzeptierten Antwort für Folgendes kombinieren. Beachten Sie, dass ich hier die Vorlage geändert habe, indem ich die Prüfung auf Ganzzahltypen entfernt habe. Diemake_unsigned
Verwendung kann ausreichen, um Sicherheitsgarantien für den Kompilierungszeittyp zu erstellen.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;
quelle
Ich denke, wir vermissen eine Erklärung, wie diese Typkonvertierungen funktionieren.
char
ist plattformabhängigsigned
oderunsigned
. In x86char
entsprichtsigned char
.Wenn ein integraler Typ (
char
,short
,int
,long
) zu einem größeren Kapazitätstyp umgewandelt wird, wird die Umwandlung hergestellt von Nullen links im Fall der Zugabeunsigned
für Typen und durch Vorzeichenerweiterungsigned
diejenigen. Die Vorzeichenerweiterung besteht darin, das höchstwertige (ganz links stehende) Bit der ursprünglichen Zahl nach links zu replizieren, bis die Bitgröße des Zieltyps erreicht ist.Wenn ich mich also in einem
signed char
Standardsystem befinde und dies tue:char a = 0xF0; // Equivalent to the binary: 11110000 std::cout << std::hex << static_cast<int>(a);
Wir würden erhalten,
F...F0
da das führende1
Bit erweitert wurde.Wenn wir sicherstellen möchten, dass wir nur
F0
in einem beliebigen System drucken , müssen wir einen zusätzlichen Zwischentyp in a umwandeln,unsigned char
sodass stattdessen Nullen hinzugefügt werden und, da sie für eine Ganzzahl mit nur 8 Bit nicht von Bedeutung sind, nicht gedruckt werden:char a = 0xF0; // Equivalent to the binary: 11110000 std::cout << std::hex << static_cast<int>(static_cast<unsigned char>(a));
Dies erzeugt
F0
quelle
Wenn Sie vorgefüllte und signierte Zeichen verwenden, achten Sie darauf, keine unerwünschten Fs anzuhängen
char out_character = 0xBE; cout << setfill('0') << setw(2) << hex << unsigned short(out_character);
Drucke: ffbe
Verwenden von int anstelle von kurzen Ergebnissen in ffffffbe
Um unerwünschte Fs zu vermeiden, können Sie sie leicht ausblenden.
char out_character = 0xBE; cout << setfill('0') << setw(2) << hex << unsigned short(out_character) & 0xFF;
quelle
Dies wird auch funktionieren:
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; }
quelle
Ich habe auf diese 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;
quelle