Da intero a stringa esadecimale in C ++


127

Come posso convertire un numero intero in una stringa esadecimale in C ++ ?

Posso trovare alcuni modi per farlo, ma per lo più sembrano mirati a C. Non sembra che ci sia un modo nativo per farlo in C ++. Tuttavia è un problema piuttosto semplice; Ne ho uno intche vorrei convertire in una stringa esadecimale per la stampa successiva.

Risposte:


225

Usa <iomanip>'s std::hex. Se stampi, invialo a std::cout, altrimenti usastd::stringstream

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

È possibile anteporre il primo <<con << "0x"o quello che vuoi, se lo si desidera.

Altre manip di interesse sono std::oct(ottale) e std::dec(torna al decimale).

Un problema che potresti incontrare è il fatto che questo produce la quantità esatta di cifre necessarie per rappresentarlo. Puoi usare setfille setwquesto per aggirare il problema:

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

Quindi, infine, suggerirei una tale funzione:

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

7
@MSalters - al contrario. Metti alla prova il tuo suggerimento sul inttipo;)
Kornel Kisielewicz

2
@ LexFridman, per emettere esattamente la quantità di cifre esadecimali necessarie. Perché emettere 8 cifre se il tipo è uint8_t?
Kornel Kisielewicz

16
AVVISO: questo non funzionerà per byte singolo perché char è sempre minacciato come char
ov7a

5
Hai anche bisogno di #include <sstream>
David Gausmann,

2
Se sto formattazione multipli interi, sembra che std::setwha bisogno di essere uscita al flusso per ogni int, mentre std::hex, std::setfill, std::uppercase, ... solo bisogno di essere inviato al flusso di output una volta. Questo sembra incoerente?
wcochran

39

Per renderlo più leggero e veloce suggerisco di utilizzare il riempimento diretto di uno spago.

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

Funzionerà per qualsiasi tipo? Intendo anche double, float, uint8_t?
SR

@SR Funziona per i tipi integrali, non per doublee float(e non per i puntatori)
Wolf

... un mix molto pragmatico (ma valido) di C e C ++, non sono sicuro della velocità ... per i miei gusti , è un po 'denso.
Wolf

Grazie, brillante risposta. Portare una libreria in streaming "solo" per farlo sembra un tale spreco.
DeveloperChris

1
Questo stampa 0000FFFFper 0xFFFF. Preferisco avere 0xFFFFcome output.
DrumM

24

Da usare std::stringstreamper convertire interi in stringhe e i suoi speciali manipolatori per impostare la base. Ad esempio in questo modo:

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

14

Basta stamparlo come numero esadecimale:

int i = /* ... */;
std::cout << std::hex << i;

8
Lo userei std::cout<<std::hex<<i<<std::dec;, altrimenti tutti i numeri interi che vengono trasmessi in streaming in seguito saranno in esadecimale. Non è necessario farlo per le altre risposte che usano stringstreamperché il flusso viene scartato dopo essere stato utilizzato, ma coutvive per sempre.
Mark Lakata

8

Puoi provare quanto segue. Sta funzionando...

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

1
una bella risposta, ma attenzione che to_stringfa parte dello spazio dei nomi stdin C ++ 11
Alex

@Alex sì, è il 2014 dopotutto ... il cielo non voglia che dovremo iniziare a trattare con C ++ 14 presto.
Alex

7

Questa domanda è vecchia, ma sono sorpreso perché nessuno ha menzionato boost::format:

cout << (boost::format("%x") % 1234).str();  // output is: 4d2

4
int num = 30;
std::cout << std::hex << num << endl; // This should give you hexa- decimal of 30

4

Grazie al commento di Lincoln qui sotto, ho cambiato questa risposta.

La risposta seguente gestisce correttamente gli int a 8 bit in fase di compilazione. Tuttavia, richiede C ++ 17. Se non hai C ++ 17, dovrai fare qualcos'altro (ad esempio fornire overload di questa funzione, uno per uint8_t e uno per int8_t, o usare qualcosa oltre a "if constexpr", forse 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();
}

Risposta originale che non gestisce correttamente gli int a 8 bit come pensavo:

La risposta di Kornel Kisielewicz è ottima. Ma una leggera aggiunta aiuta a catturare i casi in cui stai chiamando questa funzione con argomenti del modello che non hanno senso (es. Float) o che comporterebbero errori di compilazione disordinati (es. Tipo definito dall'utente).

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

Ho modificato questo per aggiungere una chiamata a std :: to_string perché i tipi interi a 8 bit (ad esempio i std::uint8_tvalori passati) a std::stringstreamsono trattati come char, che non ti dà il risultato desiderato. Passando tali numeri interi astd::to_string gestirli correttamente e non danneggia le cose quando si usano altri tipi interi più grandi. Ovviamente potresti subire un leggero calo delle prestazioni in questi casi poiché la chiamata std :: to_string non è necessaria.

Nota: avrei semplicemente aggiunto questo in un commento alla risposta originale, ma non ho il rappresentante per commentare.


nel mio test std :: to_string (i) non stampa gli interi std :: uint8_t come esadecimale. Penso che questo possa dover avere condizioni separate per entrambi i tipi uint8_t e int8_t, poiché devono essere espressi su numeri interi più grandi.
Lincoln,

1
@ Lincoln Hai ragione. Non so cosa stavo facendo in quel momento (mesi fa ora) che mi ha fatto pensare che to_string gestisse gli int a 8 bit. Sono anche tornato alla versione del compilatore che penso stavo usando allora, solo per ricontrollare, ma to_string non ha funzionato come avevo detto. Quindi chi lo sa? Comunque, grazie per aver capito: ho modificato la risposta a qualcosa che dovrebbe funzionare correttamente.
Perdita di mentalità

1
Questo funzionerà ancora in modo imprevisto per char(che è diverso da entrambi uint8_te int8_tnella maggior parte delle implementazioni (dove sono rispettivamente unsigned chare signed char)).
Ruslan,

@ruslan Sì, anche i tipi bool e wide char corrispondono tutti a std :: is_integral e non falliranno nell'asserzione. Ma poiché char è, secondo lo std., Un tipo univoco garantito, così come i tipi wide char, puoi gestirli tutti se lo desideri (le eccezioni sono un / signed char, che corrisponde al tipo integrale un / signed di qualunque larghezza a byte si trova sulla macchina corrente, in genere int8, quindi non può essere filtrato se si desidera far corrispondere anche gli int della stessa larghezza). Puoi rifiutare char, wide chars, bool aggiungendo più termini a static_assert: ... && !std::is_same_v<char, T> && !std::is_same_v<bool, T>ecc ...
Loss Mentality

2

Per quelli di voi che hanno capito che molti / la maggior parte di ios::fmtflagsloro non funzionano std::stringstreamancora come l'idea del modello che Kornel ha pubblicato molto tempo fa, il seguente funziona ed è relativamente pulito:

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

9
Non dovresti semplicemente restituire buf.str ()?
ruipacheco

2

Lo voglio:

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

Dai un'occhiata alla risposta SO da iFreilicht e al file di intestazione del modello richiesto da qui GIST !


2

Dai un'occhiata alla mia soluzione, [1] che ho copiato letteralmente dal mio progetto, quindi è incluso un documento API in tedesco. Il mio obiettivo era combinare flessibilità e sicurezza all'interno delle mie effettive esigenze: [2]

  • nessun 0xprefisso aggiunto: il chiamante può decidere
  • deduzione automatica della larghezza : meno battitura
  • controllo esplicito della larghezza : ampliamento per la formattazione, restringimento (senza perdita di dati) per risparmiare spazio
  • in grado di affrontare long long
  • limitato ai tipi integrali : evitare sorprese con conversioni silenziose
  • facilità di comprensione
  • nessun limite hardcoded
#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] basato sulla risposta di Kornel Kisielewicz
[2] Tradotto nella lingua di CppTest , ecco come si legge:

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

1
Potrebbe mostrare la detrazione della larghezza con ad esempioTEST_ASSERT(int_to_hex(short(0x12)) == "0012");
Gare di leggerezza in orbita

2

Codice per il tuo riferimento:

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

4
Questo in realtà non si aggiunge alle risposte esistenti, ed è inutile esplicitamente clearil sstream(verrà comunque distrutto quando la funzione ritorna sulla riga successiva). Potresti evitare il nome hexStrcompletamente e solo return sstream.str();senza clearing e ottenere lo stesso effetto, riducendo quattro righe di codice a una.
ShadowRanger

1
quando lo scopo del forum è capire le cose e l'utilizzo. essere verbosi è molto meglio fornire un'immagine chiara che salvare le righe. la domanda non era su un codice ottimizzato e la risposta cerca di fornire un metodo modulare per gestire tali conversioni. @ShadowRanger
parasrish

1
Qual è lo scopo di sstream.clear();? L' sstreamoggetto viene automaticamente distrutto alla fine dell'ambito, quindi return sstream.str();lo farebbe.
Wolf

sstream.clearcancellerà semplicemente il contenuto, prima che lo stream termini con scope end (per cancellare eventuali flag fail e eof con clear). In effetti, quando l'ambito muore, con la durata della variabile stream, e quindi sstream.strpuò essere utilizzato per restituire in base al valore. [Riferimento: cplusplus.com/reference/ios/ios/clear/]
parasrish

2

La mia soluzione. Sono consentiti solo i tipi integrali.

Aggiornare. È possibile impostare il prefisso opzionale 0x nel secondo parametro.

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

Risultati:
0xfe
0xfe
0xfffffffe
0xfffffffffffffffe

fe
fe fffffffe
fffffffffffffffe


1

Vorrei aggiungere una risposta per godere della bellezza del linguaggio C ++. La sua adattabilità a lavorare ad alti e bassi livelli. Buona programmazione.

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

Esempi:

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"

Questo utilizza alcune tecniche non viste nelle altre risposte. Puoi modificare la risposta per includere qualche spiegazione su come e perché funziona?
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;

Utilizzando void pointer:

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

Aggiunta di 0x:

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

Uscite:

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

-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 (indirizzo)
6946500 (indirizzo da dec)
0x69fec4 (indirizzo da dec, output in esadecimale)


istintivamente è andato con questo ...
int address = (int) & var;

visto questo altrove ...
indirizzo lungo non firmato = reinterpret_cast (& var);

il commento mi ha detto che è corretto ...
int address = (int) & var;

a proposito di leggerezza ben coperta , dove sei? stanno ottenendo troppi Mi piace!


Questa domanda è già stata ben trattata; cosa aggiunge la tua risposta a quelle già pubblicate? E cosa c'entrano gli indirizzi?
Gare di leggerezza in orbita

@LightnessRacesinOrbit non è stato chiuso, vero? l'hai detto agli ultimi 3 ragazzi che hanno commentato? questo diventa solo più pertinente per quello che stavo cercando. potrebbe aiutare qualcun altro. e cosa c'entrano gli indirizzi? chi legge gli indirizzi in decimale? è un vero esempio.
Puddle

Pubblicare la stessa risposta che era già stata pubblicata quasi nove anni fa non è ritenuto utile, e questa introduzione di puntatori all'equazione sembra essere venuta dal nulla: l'OP non chiede informazioni sui puntatori. Inoltre, no, non sarebbe unsigned longma std::intptr_t.
Gare di leggerezza in orbita

intptr_t = int ... uintptr_t = unsigned int ... gli indirizzi di memoria sono firmati adesso? e quanta memoria ti dà un int?
Puddle

Stai perdendo il punto. Un intptr_tpuò memorizzare qualsiasi puntatore sulla piattaforma di costruzione; questo non è [necessariamente] vero per unsigned int. E, ancora, niente di tutto questo è rilevante per la domanda. Nessun'altra risposta da parte mia
Lightness Races in Orbit
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.