Integer-to-Hex-String in C ++

127

Wie konvertiere ich eine Ganzzahl in eine Hex-Zeichenfolge in C ++ ?

Ich kann einige Möglichkeiten finden, dies zu tun, aber sie scheinen hauptsächlich auf C ausgerichtet zu sein. Es scheint nicht, dass es in C ++ eine native Möglichkeit gibt, dies zu tun. Es ist jedoch ein ziemlich einfaches Problem; Ich habe eine, intdie ich zum späteren Drucken in eine Hex-Zeichenfolge konvertieren möchte.

kryptobs2000
quelle

Antworten:

225

Verwenden Sie <iomanip>'s std::hex. Wenn Sie drucken, senden Sie es einfach an std::cout, wenn nicht, dann verwenden Siestd::stringstream

std::stringstream stream;
stream << std::hex << your_int;
std::string result( stream.str() );

Sie können das erste <<mit << "0x"oder nach Belieben voranstellen, wenn Sie möchten.

Andere interessante Manips sind std::oct(oktal) und std::dec(zurück zur Dezimalstelle).

Ein Problem, auf das Sie möglicherweise stoßen, ist die Tatsache, dass dies genau die Anzahl der Stellen ergibt, die zur Darstellung erforderlich sind. Sie können setfillund setwdies verwenden, um das Problem zu umgehen:

stream << std::setfill ('0') << std::setw(sizeof(your_type)*2) 
       << std::hex << your_int;

Zum Schluss würde ich eine solche Funktion vorschlagen:

template< typename T >
std::string int_to_hex( T i )
{
  std::stringstream stream;
  stream << "0x" 
         << std::setfill ('0') << std::setw(sizeof(T)*2) 
         << std::hex << i;
  return stream.str();
}
Kornel Kisielewicz
quelle
7
@ MSalters - ganz im Gegenteil. Testen Sie Ihren Vorschlag auf dem intTyp;)
Kornel Kisielewicz
2
@LexFridman, um genau die Anzahl der Hex-Ziffern nach Bedarf auszugeben. Warum 8 Ziffern ausgeben, wenn der Typ uint8_t ist?
Kornel Kisielewicz
15
WARNUNG: Dies funktioniert nicht für einzelne Bytes, da char immer als char
bedroht ist
5
Sie benötigen auch #include <sstream>
David Gausmann
2
Wenn ich mehrere Ints bin Formatierung, so scheint es , dass std::setwBedarf für jeden int Ausgabe an den Strom zu sein, während std::hex, std::setfill, std::uppercase, ... nur einmal in den Ausgabestream gesendet werden müssen. Das scheint inkonsistent?
Wcochran
39

Um es leichter und schneller zu machen, schlage ich vor, eine Schnur direkt zu füllen.

template <typename I> std::string n2hexstr(I w, size_t hex_len = sizeof(I)<<1) {
    static const char* digits = "0123456789ABCDEF";
    std::string rc(hex_len,'0');
    for (size_t i=0, j=(hex_len-1)*4 ; i<hex_len; ++i,j-=4)
        rc[i] = digits[(w>>j) & 0x0f];
    return rc;
}
AndreyS Scherbakov
quelle
Funktioniert das für jeden Typ? Ich meine auch double, float, uint8_t?
SR
@ SR Es funktioniert für integrale Typen, nicht für doubleund float(und nicht für Zeiger)
Wolf
... eine sehr pragmatische (aber gültige) Mischung aus C und C ++, ich bin mir nicht sicher über die Geschwindigkeit ... für meinen Geschmack ist es ein bisschen dicht.
Wolf
Danke, brillante Antwort. Eine Stream-Bibliothek "nur" dazu zu bringen, scheint eine solche Verschwendung zu sein.
DeveloperChris
1
Dies druckt 0000FFFFfür 0xFFFF. Ich bevorzuge 0xFFFFals Ausgabe zu haben .
DrumM
24

Verwenden Sie std::stringstreamdiese Option , um Ganzzahlen in Zeichenfolgen umzuwandeln, und verwenden Sie spezielle Manipulatoren, um die Basis festzulegen. Zum Beispiel so:

std::stringstream sstream;
sstream << std::hex << my_integer;
std::string result = sstream.str();
Phlipsy
quelle
14

Drucken Sie es einfach als Hexadezimalzahl aus:

int i = /* ... */;
std::cout << std::hex << i;
Etienne de Martel
quelle
7
Ich würde verwenden std::cout<<std::hex<<i<<std::dec;, sonst werden alle Ganzzahlen, die später gestreamt werden, hexadezimal sein. Sie müssen dies nicht für die anderen Antworten tun, die verwendet werden, stringstreamda der Stream nach seiner Verwendung verworfen wird, aber coutfür immer lebt.
Mark Lakata
8

Sie können Folgendes versuchen. Es funktioniert...

#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using namespace std;

template <class T>
string to_string(T t, ios_base & (*f)(ios_base&))
{
  ostringstream oss;
  oss << f << t;
  return oss.str();
}

int main ()
{
  cout<<to_string<long>(123456, hex)<<endl;
  system("PAUSE");
  return 0;
}
Mahmut EFE
quelle
1
Eine nette Antwort, aber Vorsicht, das to_stringist Teil des Namespace stdin C ++ 11
Alex
@Alex ja, es ist doch 2014 ... der Himmel verbietet uns, bald mit C ++ 14 zu beginnen.
Alex
7

Diese Frage ist alt, aber ich bin überrascht, warum niemand erwähnt hat boost::format:

cout << (boost::format("%x") % 1234).str();  // output is: 4d2
s4eed
quelle
4
int num = 30;
std::cout << std::hex << num << endl; // This should give you hexa- decimal of 30
Mahesh
quelle
4

Dank Lincolns Kommentar unten habe ich diese Antwort geändert.

Die folgende Antwort behandelt 8-Bit-Ints zur Kompilierungszeit ordnungsgemäß. Es erfordert jedoch C ++ 17. Wenn Sie nicht über C ++ 17 verfügen, müssen Sie etwas anderes tun (z. B. Überladungen dieser Funktion bereitstellen, eine für uint8_t und eine für int8_t, oder etwas anderes als "if constexpr" verwenden, möglicherweise enable_if).

template< typename T >
std::string int_to_hex( T i )
{
    // Ensure this function is called with a template parameter that makes sense. Note: static_assert is only available in C++11 and higher.
    static_assert(std::is_integral<T>::value, "Template argument 'T' must be a fundamental integer type (e.g. int, short, etc..).");

    std::stringstream stream;
    stream << "0x" << std::setfill ('0') << std::setw(sizeof(T)*2) << std::hex;

    // If T is an 8-bit integer type (e.g. uint8_t or int8_t) it will be 
    // treated as an ASCII code, giving the wrong result. So we use C++17's
    // "if constexpr" to have the compiler decides at compile-time if it's 
    // converting an 8-bit int or not.
    if constexpr (std::is_same_v<std::uint8_t, T>)
    {        
        // Unsigned 8-bit unsigned int type. Cast to int (thanks Lincoln) to 
        // avoid ASCII code interpretation of the int. The number of hex digits 
        // in the  returned string will still be two, which is correct for 8 bits, 
        // because of the 'sizeof(T)' above.
        stream << static_cast<int>(i);
    }        
    else if (std::is_same_v<std::int8_t, T>)
    {
        // For 8-bit signed int, same as above, except we must first cast to unsigned 
        // int, because values above 127d (0x7f) in the int will cause further issues.
        // if we cast directly to int.
        stream << static_cast<int>(static_cast<uint8_t>(i));
    }
    else
    {
        // No cast needed for ints wider than 8 bits.
        stream << i;
    }

    return stream.str();
}

Ursprüngliche Antwort, die 8-Bit-Ints nicht richtig verarbeitet, wie ich dachte:

Die Antwort von Kornel Kisielewicz ist großartig. Ein kleiner Zusatz hilft jedoch dabei, Fälle zu erfassen, in denen Sie diese Funktion mit Vorlagenargumenten aufrufen, die keinen Sinn ergeben (z. B. float) oder die zu unordentlichen Compilerfehlern führen würden (z. B. benutzerdefinierter Typ).

template< typename T >
std::string int_to_hex( T i )
{
  // Ensure this function is called with a template parameter that makes sense. Note: static_assert is only available in C++11 and higher.
  static_assert(std::is_integral<T>::value, "Template argument 'T' must be a fundamental integer type (e.g. int, short, etc..).");

  std::stringstream stream;
  stream << "0x" 
         << std::setfill ('0') << std::setw(sizeof(T)*2) 
         << std::hex << i;

         // Optional: replace above line with this to handle 8-bit integers.
         // << std::hex << std::to_string(i);

  return stream.str();
}

Ich habe dies bearbeitet, um std :: to_string einen Aufruf hinzuzufügen, da 8-Bit-Integer-Typen (z. B. übergebene std::uint8_tWerte) std::stringstreamals char behandelt werden, wodurch Sie nicht das gewünschte Ergebnis erhalten. Das Übergeben solcher Ganzzahlen, std::to_stringum sie korrekt zu behandeln, schadet nichts, wenn andere, größere Ganzzahltypen verwendet werden. Natürlich kann es in diesen Fällen zu einem leichten Leistungseinbruch kommen, da der Aufruf von std :: to_string nicht erforderlich ist.

Hinweis: Ich hätte dies nur in einem Kommentar zur ursprünglichen Antwort hinzugefügt, aber ich habe nicht den Repräsentanten, um einen Kommentar abzugeben.

Verlustmentalität
quelle
In meinem Test druckt std :: to_string (i) keine std :: uint8_t-Ganzzahlen als Hex. Ich denke, dies muss möglicherweise separate Bedingungen für die Typen uint8_t und int8_t haben, da sie in größere Ganzzahlen umgewandelt werden müssen.
Lincoln
1
@ Lincoln Du hast recht. Ich weiß nicht, was ich damals (vor Monaten) gemacht habe, was mich dazu gebracht hat, mit 8-Bit-Ints umzugehen. Ich bin sogar zu der Compiler-Version zurückgekehrt, die ich damals verwendet habe, nur um es noch einmal zu überprüfen, aber to_string hat nicht so funktioniert, wie ich es gesagt habe. Also wer weiß? Wie auch immer, danke, dass du das verstanden hast - ich habe die Antwort auf etwas bearbeitet, das richtig funktionieren sollte.
Verlustmentalität
1
Dies funktioniert immer noch unerwartet für char(was sich von beiden uint8_tund int8_tin den meisten Implementierungen unterscheidet (wo sie sich jeweils befinden unsigned charund signed char)).
Ruslan
@ruslan Ja, auch Bool- und Wide-Char-Typen stimmen mit std :: is_integral überein und werden die Bestätigung nicht verfehlen. Da char laut Standard ein garantierter eindeutiger Typ ist, wie auch die Wide-Char-Typen, können Sie alle auf Wunsch behandeln (Ausnahmen sind un / signierte Zeichen, die mit dem nicht / signierten Integraltyp gleicher Breite a übereinstimmen Das Byte befindet sich auf dem aktuellen Computer (normalerweise int8) und kann daher nicht gefiltert werden, wenn Sie auch Ints mit derselben Breite abgleichen möchten. Sie können char, wide chars, bools ablehnen, indem Sie dem static_assert weitere Begriffe hinzufügen: ... && !std::is_same_v<char, T> && !std::is_same_v<bool, T>etc ...
Loss Mentality
2

Für diejenigen unter Ihnen, die herausgefunden haben, dass viele / die meisten ios::fmtflagsnoch nicht mit std::stringstreamder Vorlagenidee arbeiten, die Kornel vor langer Zeit veröffentlicht hat, funktioniert Folgendes und ist relativ sauber:

#include <iomanip>
#include <sstream>


template< typename T >
std::string hexify(T i)
{
    std::stringbuf buf;
    std::ostream os(&buf);


    os << "0x" << std::setfill('0') << std::setw(sizeof(T) * 2)
       << std::hex << i;

    return buf.str().c_str();
}


int someNumber = 314159265;
std::string hexified = hexify< int >(someNumber);
Kevin
quelle
9
Sollten Sie nicht einfach buf.str () zurückgeben?
Ruipacheco
2

Ich mache:

int hex = 10;      
std::string hexstring = stringFormat("%X", hex);  

Schauen Sie sich die SO- Antwort von iFreilicht und die erforderliche Template-Header-Datei von hier an. GIST !

CarpeDiemKopi
quelle
2

Schauen Sie sich einfach meine Lösung an, [1] die ich wörtlich aus meinem Projekt kopiert habe, damit dort ein deutsches API-Dokument enthalten ist. Mein Ziel war es, Flexibilität und Sicherheit innerhalb meiner tatsächlichen Bedürfnisse zu kombinieren: [2]

  • Kein 0xPräfix hinzugefügt: Anrufer kann entscheiden
  • automatischer Breitenabzug : weniger Eingabe
  • explizite Breitensteuerung : Verbreiterung zur Formatierung, (verlustfreies) Verkleinern, um Platz zu sparen
  • fähig für den Umgang mit long long
  • beschränkt auf integrale Typen : Vermeiden Sie Überraschungen durch stille Konvertierungen
  • Leichtigkeit des Verständnisses
  • Keine fest codierte Grenze
#include <string>
#include <sstream>
#include <iomanip>

/// Vertextet einen Ganzzahlwert val im Hexadezimalformat.
/// Auf die Minimal-Breite width wird mit führenden Nullen aufgefüllt;
/// falls nicht angegeben, wird diese Breite aus dem Typ des Arguments
/// abgeleitet. Funktion geeignet von char bis long long.
/// Zeiger, Fließkommazahlen u.ä. werden nicht unterstützt, ihre
/// Übergabe führt zu einem (beabsichtigten!) Compilerfehler.
/// Grundlagen aus: http://stackoverflow.com/a/5100745/2932052
template <typename T>
inline std::string int_to_hex(T val, size_t width=sizeof(T)*2)
{
    std::stringstream ss;
    ss << std::setfill('0') << std::setw(width) << std::hex << (val|0);
    return ss.str();
}

[1] basierend auf der Antwort von Kornel Kisielewicz
[2] In die Sprache von CppTest übersetzt lautet dies folgendermaßen:

TEST_ASSERT(int_to_hex(char(0x12)) == "12");
TEST_ASSERT(int_to_hex(short(0x1234)) == "1234");
TEST_ASSERT(int_to_hex(long(0x12345678)) == "12345678");
TEST_ASSERT(int_to_hex((long long)(0x123456789abcdef0)) == "123456789abcdef0");
TEST_ASSERT(int_to_hex(0x123, 1) == "123");
TEST_ASSERT(int_to_hex(0x123, 8) == "00000123");
// with deduction test as suggested by Lightness Races in Orbit:
TEST_ASSERT(int_to_hex(short(0x12)) == "0012"); 
Wolf
quelle
1
Könnte den Breitenabzug mit zBTEST_ASSERT(int_to_hex(short(0x12)) == "0012");
Leichtigkeitsrennen im Orbit
2

Code als Referenz:

#include <iomanip>
#include <sstream>
...
string intToHexString(int intValue) {

    string hexStr;

    /// integer value to hex-string
    std::stringstream sstream;
    sstream << "0x"
            << std::setfill ('0') << std::setw(2)
    << std::hex << (int)intValue;

    hexStr= sstream.str();
    sstream.clear();    //clears out the stream-string

    return hexStr;
}
Parasrish
quelle
4
Dies ist nicht wirklich zu den bestehenden Antworten hinzufügen, und es ist sinnlos , um explizit cleardie sstream(wird es , wenn die Funktion zurückkehrt sowieso in der nächsten Zeile zerstört werden). Sie können den Namen hexStrganz und einfach vermeiden, return sstream.str();ohne clearden gleichen Effekt zu erzielen, indem Sie vier Codezeilen auf eine reduzieren.
ShadowRanger
1
wenn der Zweck des Forums darin besteht, die Dinge und die Verwendung zu verstehen. Ausführlich zu sein ist weitaus besser, um ein klares Bild zu liefern, als Zeilen zu speichern. Die Frage bezog sich nicht auf optimierten Code, und die Antwort versucht, eine modulare Methode für den Umgang mit solchen Konvertierungen bereitzustellen. @ ShadowRanger
Parasrish
1
Was ist der Zweck von sstream.clear();? Das sstreamObjekt wird am Ende des Bereichs automatisch zerstört return sstream.str();.
Wolf
sstream.clearlöscht nur den Inhalt, bevor der Stream mit dem Ende des Bereichs endet (um alle Fehler- und Eof-Flags mit clear zu löschen). In der Tat, wenn der Bereich stirbt, mit der Lebensdauer der Stream-Variablen, und sstream.strkann daher verwendet werden, um nach Wert zurückzukehren. [Referenz: cplusplus.com/reference/ios/ios/clear/]
Parasrish
2

Meine Lösung. Es sind nur ganzzahlige Typen zulässig.

Aktualisieren. Sie können das optionale Präfix 0x im zweiten Parameter festlegen.

definition.h

#include  <iomanip>
#include <sstream>

template <class T, class T2 = typename std::enable_if<std::is_integral<T>::value>::type>
static std::string ToHex(const T & data, bool addPrefix = true);



template<class T, class>
inline std::string Convert::ToHex(const T & data, bool addPrefix)
{
    std::stringstream sstream;
    sstream << std::hex;
    std::string ret;
    if (typeid(T) == typeid(char) || typeid(T) == typeid(unsigned char) || sizeof(T)==1)
    {
        sstream << static_cast<int>(data);
        ret = sstream.str();
        if (ret.length() > 2)
        {
            ret = ret.substr(ret.length() - 2, 2);
        }
    }
    else
    {
        sstream << data;
        ret = sstream.str();
    }
    return (addPrefix ? u8"0x" : u8"") + ret;
}

main.cpp

#include <definition.h>
int main()
{
    std::cout << ToHex<unsigned char>(254) << std::endl;
    std::cout << ToHex<char>(-2) << std::endl;
    std::cout << ToHex<int>(-2) << std::endl;
    std::cout << ToHex<long long>(-2) << std::endl;

    std::cout<< std::endl;
    std::cout << ToHex<unsigned char>(254, false) << std::endl;
    std::cout << ToHex<char>(-2, false) << std::endl;
    std::cout << ToHex<int>(-2, false) << std::endl;
    std::cout << ToHex<long long>(-2, false) << std::endl;
    return 0;
}

Ergebnisse:
0xfe
0xfe
0xfffffffe
0xfffffffffffffffe

fe
fe FFFFFFFE
fffffffffffffffe

Joma
quelle
1

Ich möchte eine Antwort hinzufügen, um die Schönheit der C ++ - Sprache zu genießen. Seine Anpassungsfähigkeit an Arbeiten auf hohem und niedrigem Niveau. Viel Spaß beim Programmieren.

public:template <class T,class U> U* Int2Hex(T lnumber, U* buffer)
{
    const char* ref = "0123456789ABCDEF";
    T hNibbles = (lnumber >> 4);

    unsigned char* b_lNibbles = (unsigned char*)&lnumber;
    unsigned char* b_hNibbles = (unsigned char*)&hNibbles;

    U* pointer = buffer + (sizeof(lnumber) << 1);

    *pointer = 0;
    do {
        *--pointer = ref[(*b_lNibbles++) & 0xF];
        *--pointer = ref[(*b_hNibbles++) & 0xF];
    } while (pointer > buffer);

    return buffer;
}

Beispiele:

char buffer[100] = { 0 };
Int2Hex(305419896ULL, buffer);//returns "0000000012345678"
Int2Hex(305419896UL, buffer);//returns "12345678"
Int2Hex((short)65533, buffer);//returns "FFFD"
Int2Hex((char)18, buffer);//returns "12"

wchar_t buffer[100] = { 0 };
Int2Hex(305419896ULL, buffer);//returns L"0000000012345678"
Int2Hex(305419896UL, buffer);//returns L"12345678"
Int2Hex((short)65533, buffer);//returns L"FFFD"
Int2Hex((char)18, buffer);//returns L"12"
ORParga ORParga
quelle
Dies verwendet einige Techniken, die in den anderen Antworten nicht zu sehen sind. Können Sie die Antwort bitte bearbeiten, um zu erklären, wie und warum sie funktioniert?
Jason Aller
0
#include <iostream> 
#include <sstream>  

int main()
{
unsigned int i = 4967295; // random number
std::string str1, str2;
unsigned int u1, u2;

std::stringstream ss;

Void-Zeiger verwenden:

// INT to HEX
ss << (void*)i;       // <- FULL hex address using void pointer
ss >> str1;          //     giving address value of one given in decimals.
ss.clear();         // <- Clear bits
// HEX to INT
ss << std::hex << str1;   // <- Capitals doesn't matter so no need to do extra here
ss >> u1;
ss.clear();

0x hinzufügen:

// INT to HEX with 0x
ss << "0x" << (void*)i;   // <- Same as above but adding 0x to beginning
ss >> str2;
ss.clear();
// HEX to INT with 0x
ss << std::hex << str2;   // <- 0x is also understood so need to do extra here
ss >> u2;
ss.clear();

Ausgänge:

std::cout << str1 << std::endl; // 004BCB7F
std::cout << u1 << std::endl;   // 4967295
std::cout << std::endl;
std::cout << str2 << std::endl; // 0x004BCB7F
std::cout << u2 << std::endl;   // 4967295


return 0;
}
Olli V.
quelle
-1
int var = 20;
cout <<                          &var << endl;
cout <<                     (int)&var << endl;
cout << std::hex << "0x" << (int)&var << endl << std::dec; // output in hex, reset back to dec

0x69fec4 (Adresse)
6946500 (Adresse zu dec)
0x69fec4 (Adresse zu dec, Ausgabe in hex)


ging instinktiv mit diesem ...
int address = (int) & var;

habe das woanders gesehen ...
unsigned long address = reinterpret_cast (& var);

Kommentar sagte mir, dass dies korrekt ist ...
int address = (int) & var;

Apropos gut bedeckte Leichtigkeit, wo bist du? Sie bekommen zu viele Likes!

Pfütze
quelle
Diese Frage wurde bereits ausführlich behandelt. Was fügt Ihre Antwort zu den bereits veröffentlichten hinzu? Und was haben Adressen damit zu tun?
Leichtigkeitsrennen im Orbit
@ LightnessRacesinOrbit es wurde nicht geschlossen, oder? Hast du das zu den letzten 3 Jungs gesagt, die das kommentiert haben? Das bringt mich auf den Punkt, wonach ich gesucht habe. es könnte jemand anderem helfen. und was haben adressen damit zu tun? Wer liest Adressen dezimal? Es ist ein echtes Beispiel.
Pfütze
Die gleiche Antwort zu veröffentlichen, die bereits vor fast neun Jahren veröffentlicht wurde, wird nicht als nützlich erachtet, und diese Einführung von Zeigern auf die Gleichung scheint aus heiterem Himmel gekommen zu sein - das OP fragt nicht nach Zeigern. Außerdem nein, das wäre es unsigned longaber nicht std::intptr_t.
Leichtigkeitsrennen im Orbit
intptr_t = int ... uintptr_t = unsigned int ... sind die Speicheradressen jetzt signiert? und wie viel Gedächtnis gibt dir ein Int?
Pfütze
Sie verpassen den Punkt. Ein intptr_tkann einen beliebigen Zeiger auf der Build-Plattform speichern. das ist nicht [notwendigerweise] wahr unsigned int. Und auch hier ist nichts davon für die Frage relevant. Keine weiteren Antworten von mir
Leichtigkeitsrennen im Orbit