Entier en chaîne hexadécimale en C ++


127

Comment convertir un entier en chaîne hexadécimale dans C ++ ?

Je peux trouver des moyens de le faire, mais ils semblent principalement ciblés vers C. Il ne semble pas qu'il y ait une façon native de le faire en C ++. C'est un problème assez simple cependant; J'en ai un intque j'aimerais convertir en une chaîne hexadécimale pour une impression ultérieure.

Réponses:


225

Utilisez <iomanip>les std::hex. Si vous imprimez, envoyez-le simplement à std::cout, sinon, utilisezstd::stringstream

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

Vous pouvez ajouter le premier <<avec << "0x"ou ce que vous voulez si vous le souhaitez.

D'autres manips intéressants sont std::oct(octal) etstd::dec (retour au décimal).

Un problème que vous pouvez rencontrer est le fait que cela produit le nombre exact de chiffres nécessaires pour le représenter. Vous pouvez utiliser setfillet setwceci pour contourner le problème:

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

Alors enfin, je suggérerais une telle fonction:

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 - bien au contraire. Testez votre suggestion sur le inttype;)
Kornel Kisielewicz

2
@LexFridman, pour émettre exactement la quantité de chiffres hexadécimaux selon les besoins. Pourquoi émettre 8 chiffres si le type est un uint8_t?
Kornel Kisielewicz

16
AVERTISSEMENT: cela ne fonctionnera pas pour un octet car char est toujours menacé comme char
ov7a

5
Vous avez également besoin de #include <sstream>
David Gausmann

2
Si je suis mise en forme ints multiples, il semble que les std::setwbesoins d'être sortie au flux pour chaque entier, alors que std::hex, std::setfill, std::uppercase, ... ne doivent être envoyés au flux de sortie une fois. Cela semble incohérent?
wcochran

39

Pour le rendre plus léger et plus rapide, je suggère d'utiliser le remplissage direct d'une ficelle.

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

Cela fonctionnera-t-il pour n'importe quel type? Je veux dire aussi double, float, uint8_t?
SR

@SR Cela fonctionne pour les types intégraux, pas pour doubleet float(et pas pour les pointeurs)
Wolf

... un mélange très pragmatique (mais valide) de C et C ++, je ne suis pas sûr de la vitesse ... à mon goût , c'est un peu dense.
Wolf

Merci, réponse brillante. Apporter une bibliothèque de flux «juste» pour faire cela semble un tel gaspillage.
DeveloperChris

1
Cela imprime 0000FFFFpour 0xFFFF. Je préfère avoir 0xFFFFen sortie.
DrumM le

24

Utilisez std::stringstreampour convertir des entiers en chaînes et ses manipulateurs spéciaux pour définir la base. Par exemple comme ça:

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

14

Imprimez-le simplement sous forme de nombre hexadécimal:

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

8
J'utiliserais std::cout<<std::hex<<i<<std::dec;, sinon tous les entiers qui sont diffusés plus tard seront en hexadécimal. Vous n'avez pas besoin de le faire pour les autres réponses qui utilisent, stringstreamcar le flux est supprimé après son utilisation, mais il coutvit pour toujours.
Mark Lakata

8

Vous pouvez essayer ce qui suit. Ça marche...

#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
une bonne réponse, mais attention, cela to_stringfait partie de l'espace stdde nom en C ++ 11
Alex

@Alex oui, nous sommes en 2014 après tout ... Dieu nous en garde, nous devrons bientôt commencer à traiter avec C ++ 14.
Alex

7

Cette question est ancienne, mais je suis surpris de savoir pourquoi personne n'a mentionné 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

Grâce au commentaire de Lincoln ci-dessous, j'ai changé cette réponse.

La réponse suivante gère correctement les entiers 8 bits au moment de la compilation. Cependant, il nécessite C ++ 17. Si vous n'avez pas C ++ 17, vous devrez faire autre chose (par exemple, fournir des surcharges de cette fonction, une pour uint8_t et une pour int8_t, ou utiliser quelque chose en plus de "if constexpr", peut-être 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();
}

Réponse originale qui ne gère pas correctement les entiers 8 bits comme je le pensais:

La réponse de Kornel Kisielewicz est excellente. Mais un léger ajout permet de détecter les cas où vous appelez cette fonction avec des arguments de modèle qui n'ont pas de sens (par exemple, float) ou qui entraîneraient des erreurs de compilation désordonnées (par exemple, un type défini par l'utilisateur).

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

J'ai modifié ceci pour ajouter un appel à std :: to_string car les types entiers 8 bits (par exemple les std::uint8_tvaleurs passées) à std::stringstreamsont traités comme char, ce qui ne vous donne pas le résultat souhaité. Passer de tels entiers àstd::to_string gère correctement et ne nuit pas à l'utilisation d'autres types d'entiers plus grands. Bien sûr, vous risquez de subir un léger impact sur les performances dans ces cas, car l'appel std :: to_string n'est pas nécessaire.

Remarque: j'aurais juste ajouté ceci dans un commentaire à la réponse d'origine, mais je n'ai pas le représentant à commenter.


dans mes tests, std :: to_string (i) n'affiche pas les entiers std :: uint8_t en hexadécimal. Je pense que cela peut avoir des conditions séparées pour les types uint8_t et int8_t, car ils doivent être convertis en entiers plus grands.
Lincoln

1
@Lincoln Vous avez raison. Je ne sais pas ce que je faisais à l'époque (il y a des mois maintenant) qui m'a amené à gérer des entiers 8 bits. Je suis même retourné à la version du compilateur que je pense que j'utilisais à l'époque, juste pour vérifier, mais to_string ne fonctionnait pas comme je l'ai dit. Alors qui sait? Quoi qu'il en soit, merci d'avoir attrapé ceci - j'ai édité la réponse à quelque chose qui devrait fonctionner correctement.
Loss Mentality

1
Cela fonctionnera toujours de manière inattendue pour char(ce qui est distinct des deux uint8_tet int8_tdans la plupart des implémentations (où ils sont respectivement unsigned charet signed char)).
Ruslan

@ruslan Oui, aussi les types bool et wide char correspondent tous à std :: is_integral et n'échoueront pas l'assertion. Mais comme char est, selon la norme, un type unique garanti, comme le sont les types de caractères larges, vous pouvez tous les gérer si vous le souhaitez (les exceptions sont des caractères non / signés, qui correspondent au type intégral non signé de toute largeur a byte est sur la machine actuelle - généralement int8 - et ne peut donc pas être filtré si vous souhaitez également faire correspondre des entiers de même largeur). Vous pouvez rejeter char, wide chars, bools en ajoutant plus de termes au static_assert: ... && !std::is_same_v<char, T> && !std::is_same_v<bool, T>etc ...
Loss Mentality

2

Pour ceux d'entre vous qui ont compris que beaucoup / la plupart d'entre ios::fmtflagseux ne fonctionnent pas std::stringstreamencore comme l'idée de modèle que Kornel avait publiée il y a longtemps, ce qui suit fonctionne et est relativement propre:

#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
Ne devriez-vous pas simplement retourner buf.str ()?
ruipacheco

2

Je fais:

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

Jetez un œil à la réponse SO d'iFreilicht et au fichier d'en-tête de modèle requis à partir d'ici GIST !


2

Jetez un œil à ma solution, [1] que j'ai copiée textuellement de mon projet, donc il y a un document d'API en allemand inclus. Mon objectif était de combiner flexibilité et sécurité avec mes besoins réels: [2]

  • aucun 0xpréfixe ajouté: l'appelant peut décider
  • déduction automatique de la largeur : moins de frappe
  • contrôle de largeur explicite : élargissement pour le formatage, réduction (sans perte) pour économiser de l'espace
  • capable de gérer long long
  • restreint aux types intégraux : évitez les surprises par des conversions silencieuses
  • facilité de compréhension
  • pas de limite codée en dur
#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] basé sur la réponse de Kornel Kisielewicz
[2] Traduit dans la langue de CppTest , voici comment il se lit:

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
Pourrait montrer la déduction de largeur avec par exempleTEST_ASSERT(int_to_hex(short(0x12)) == "0012");
Courses de légèreté en orbite

2

Code pour votre référence:

#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
Cela n'ajoute pas vraiment aux réponses existantes, et il est inutile de explicitement clearle sstream(il sera détruit lorsque la fonction revient sur la ligne suivante de toute façon). Vous pouvez éviter le nom hexStrentièrement et juste return sstream.str();sans clearing et obtenir le même effet, ce qui réduit quatre lignes de code à un.
ShadowRanger

1
lorsque le but du forum est de comprendre les choses et l'utilisation. être bavard est de loin préférable pour fournir une image claire, que d'enregistrer des lignes. La question ne portait pas sur le code optimisé, et la réponse essaie de donner une méthode modulaire pour traiter de telles conversions. @ShadowRanger
parasrish

1
Quel est le but de sstream.clear();? L' sstreamobjet est automatiquement détruit à la fin de la portée, donc le return sstream.str();ferait.
Loup

sstream.cleareffacera simplement le contenu, avant que le flux ne se termine avec la fin de la portée (pour effacer tout indicateur d'échec et eof avec clear). En effet, lorsque la portée meurt, avec la durée de vie de la variable de flux, et sstream.strpeut donc être utilisée pour retourner par valeur. [Référence: cplusplus.com/reference/ios/ios/clear/]
parasrish

2

Ma solution. Seuls les types intégraux sont autorisés.

Mettre à jour. Vous pouvez définir le préfixe optionnel 0x dans le deuxième paramètre.

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

Résultats:
0xfe
0xfe
0xfffffffe
0xfffffffffffffffe

fe
fe fffffffe
fffffffffffffffe


1

Je voudrais ajouter une réponse pour profiter de la beauté du langage C ++. Son adaptabilité au travail à des niveaux élevés et bas. Bonne programmation.

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

Exemples:

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"

Cela utilise certaines techniques non vues dans les autres réponses. Pouvez-vous s'il vous plaît modifier la réponse pour inclure une explication sur comment et pourquoi cela fonctionne?
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;

Utilisation du pointeur void:

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

Ajout de 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();

Les sorties:

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 (adresse)
6946500 (adresse à déc)
0x69fec4 (adresse à déc, sortie en hexadécimal)


est allé instinctivement avec cette ...
int address = (int) & var;

vu cela ailleurs ...
adresse longue non signée = reinterpret_cast (& var);

le commentaire m'a dit que c'était correct ...
int address = (int) & var;

en parlant de légèreté bien couverte , où en êtes-vous? ils reçoivent trop de likes!


Cette question a déjà été bien couverte; qu'est-ce que votre réponse ajoute à celles déjà publiées? Et qu'est-ce que les adresses ont à voir avec cela?
Courses de légèreté en orbite

@LightnessRacesinOrbit il n'a pas été fermé n'est-ce pas? avez-vous dit cela aux 3 derniers gars qui ont commenté? cela va juste plus au point pour ce que je cherchais. cela pourrait aider quelqu'un d'autre. et qu'est-ce que les adresses ont à voir avec cela? qui lit les adresses en décimal? c'est un vrai exemple.
Puddle

Publier la même réponse qui a déjà été publiée il y a près de neuf ans n'est pas jugé utile, et cette introduction de pointeurs vers l'équation semble être sortie de nulle part - le PO ne pose pas de question sur les pointeurs. De plus, non, ce ne serait pas unsigned longmais std::intptr_t.
Courses de légèreté en orbite

intptr_t = int ... uintptr_t = unsigned int ... les adresses mémoire sont-elles signées maintenant? et combien de mémoire un int vous donne-t-il?
Puddle

Vous manquez le point. An intptr_tpeut stocker n'importe quel pointeur sur la plate-forme de construction; ce n'est pas [nécessairement] vrai de unsigned int. Et, encore une fois, rien de tout cela n'est pertinent pour la question. Aucune autre réponse de ma part
Courses de légèreté en orbite
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.