Wie drucke ich ein Zeichen ohne Vorzeichen als Hex in C++ mit ostream?
Lesezeit: 2 Minuten
Nathan Fellmann
Ich möchte mit vorzeichenlosen 8-Bit-Variablen in C++ arbeiten. Entweder unsigned char oder uint8_t machen den Trick, was die Arithmetik betrifft (was erwartet wird, da AFAIK uint8_t ist nur ein Alias für unsigned charoder so präsentiert es der Debugger.
Das Problem ist, dass, wenn ich die Variablen mit ostream in C++ ausdrucke, sie als char 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 versucht, mit uint8_taber wie ich bereits erwähnt habe, ist das typdefiniert unsigned char, also tut es dasselbe. Wie kann ich meine Variablen korrekt drucken?
Bearbeiten: Ich mache das an vielen Stellen in meinem Code. Gibt es eine Möglichkeit, wie ich dies tun kann ohne Gießen zu int Jedes Mal, wenn ich drucken möchte?
Ich denke, die Antwort von MartinStettner ist ziemlich verwirrend, ich denke nicht, dass es sich lohnt, eine zusätzliche Struktur und einen zusätzlichen Stream-Operator zu implementieren. Die Lösung von anon ist einfach und funktioniert gut genug für mich.
– tdihp
28. September 2012 um 8:38 Uhr
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, warum nicht mit Terminal-C++-Bösartigkeit aufs Ganze gehen und ein Makro verwenden!
#define HEX( x )
setw(2) << setfill('0') << hex << (int)( x )
kannst du dann sagen
cout << "a is " << HEX( a );
Bearbeiten: Allerdings ist die Lösung von MartinStettner viel schöner!
Kann ich Sie überzeugen, die bösen C-Style-Casts ein für alle Mal zu meiden? stackoverflow.com/questions/527999/…
– Konrad Rudolf
23. März 2009 um 12:54 Uhr
Nicht in diesem Fall – es ist ungefähr der einzige Ort, an dem sie meiner Meinung nach gerechtfertigt sind.
– anon
23. März 2009 um 12:57 Uhr
Ich würde es genauso machen, außer um den Cast zu vermeiden, würde ich cout << hex << int(a) verwenden; Es bedeutet dasselbe wie eine Besetzung, ohne die Besetzung. :)
– Brian Neal
23. März 2009 um 14:35 Uhr
Martin Stettner
Ich würde vorschlagen, die folgende Technik zu verwenden:
Es ist kurz zu schreiben, hat die gleiche Effizienz wie die ursprüngliche Lösung und lässt Sie wählen, ob Sie die “ursprüngliche” Zeichenausgabe verwenden möchten. Und es ist typsicher (es werden keine “bösen” Makros verwendet :-))
Solange wir Makros meiden: Um vollständiger C++ zu sein, sollten Sie nicht schreiben (int)hs.c als static_cast<int>(hs.c)? 😛
– Seth Johnson
8. Juli 2009 um 11:10 Uhr
Es gibt einen kleinen Fehler in Ihrem Code. Wenn Sie im Code ein negatives Zeichen eingeben, wird der Hex-Wert 4 Bytes statt 2. Umschalten auf unsigned char behebt das Problem.
–Ted
22. Februar 2010 um 22:47 Uhr
Ein weiterer Fehler (?) ist der oben genannte operator<< ändert den Modus des angegebenen Streams in hexadezimal: cout << hex(a) << 100 wird Sie überraschen. Sie sollten den Status des Streams speichern, bevor Sie ihn ändern, und ihn später wiederherstellen.
– musiphil
19. Juni 2012 um 20:23 Uhr
Ich bin wirklich erstaunt, wie schlecht C++ beim Konvertieren ist char zu Hex.
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 Readers Digest-Version davon, wie dies funktioniert, ist, dass der unäre +-Operator eine Typkonvertierung von no op in ein int mit der korrekten Vorzeichenbelegung erzwingt. Ein unsigned char wird also in unsigned int konvertiert, ein signed char wird in int konvertiert und ein char wird entweder in unsigned int oder int konvertiert, je nachdem, ob char auf Ihrer Plattform signiert oder nicht signiert ist (es ist für viele ein Schock, dass char etwas Besonderes ist und weder signiert noch unsigniert angegeben).
Der einzige Nachteil dieser Technik ist, dass es möglicherweise nicht offensichtlich ist, was jemandem passiert, der damit 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 klar ist.
Warum ist dies nicht die Top-Antwort? Es ist kurz und effektiv.
– James Pack
23. März 2015 um 2:22 Uhr
Bei dieser Technik werden Typen kleiner als vorzeichenerweitert unsigned int / intwas bedeutet, dass Sie für negative Zeichen mit Vorzeichen (oder z. B. int16_t) 8 Ausgabe-Nibbles erhalten, von denen die ersten 6 sind F.
– Brian McFarland
13. März 2016 um 3:29 Uhr
@BrianMcFarland Ich habe dieses Problem sogar für unsigned char bemerkt (wenn es größer als 127 ist), also habe ich es mit einer Bitmaske gelöst: (+c & 0xFF).
– Nach SE
22. November 2016 um 1:24 Uhr
@To마SE, das Unäre + ist unnötig, die binäre & wandelt sich bereits in eine um int.
– Adrian
21. Juni 2019 um 1:02 Uhr
Nun, das funktioniert bei mir:
std::cout << std::hex << (0xFF & a) << std::endl;
Wenn Sie nur werfen (int) Wie vorgeschlagen, könnte es 1s links von hinzufügen a wenn sein höchstwertiges Bit 1 ist. Wenn Sie also diese binäre UND-Operation durchführen, wird garantiert, dass die linken Bits der Ausgabe mit 0 gefüllt werden, und sie wird auch in unsigned int konvertiert, wodurch cout gezwungen wird, sie als Hex auszugeben.
Ich hoffe das hilft.
vitaut
In C++20 können Sie verwenden std::format um dies zu tun:
std::cout << std::format("a is {:x}; b is {:x}\n", a, b);
Ausgabe:
a is 0; b is ff
In der Zwischenzeit können Sie verwenden die {fmt}-Bibliothek, std::format basiert auf. {fmt} bietet auch die print Funktion, die dies noch einfacher und effizienter macht (Gottriegel):
fmt::print("a is {:x}; b is {:x}\n", a, b);
Haftungsausschluss: Ich bin der Autor von {fmt} und C++20 std::format.
Hm, anscheinend habe ich gestern das Rad neu erfunden … Aber hey, zumindest ist es diesmal ein generisches Rad 🙂 chars werden mit zwei Hex-Ziffern gedruckt, shorts mit 4 Hex-Ziffern und so weiter.
Ich denke, die Antwort von TrungTN und anon ist in Ordnung, aber MartinStettners Art, die hex()-Funktion zu implementieren, 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 “<<" einfacher zu machen:
Ich denke, die Antwort von MartinStettner ist ziemlich verwirrend, ich denke nicht, dass es sich lohnt, eine zusätzliche Struktur und einen zusätzlichen Stream-Operator zu implementieren. Die Lösung von anon ist einfach und funktioniert gut genug für mich.
– tdihp
28. September 2012 um 8:38 Uhr