web-dev-qa-db-fra.com

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

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

Je peux trouver des moyens de le faire, mais ils semblent principalement cibler le C. Il ne semble pas qu'il existe un moyen natif de le faire en C++. C'est un problème assez simple cependant; J'ai un int que je voudrais convertir en chaîne hexagonale pour une impression ultérieure.

105
kryptobs2000

Utilisez _<iomanip>_ ' std::hex . Si vous imprimez, envoyez-le simplement à _std::cout_, sinon, utilisez std::stringstream

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

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

Les autres domaines d'intérêt sont _std::oct_ (octal) et _std::dec_ (retour au format 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 setfill et setw ceci pour contourner le problème:

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

Donc, finalement, 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();
}
_
188
Kornel Kisielewicz

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

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;
}
32
AndreyS Scherbakov

Utilisez std::stringstream pour convertir les 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();
22
phlipsy

Il suffit de l’imprimer sous forme de nombre hexadécimal:

int i = /* ... */;
std::cout << std::hex << i;
13
Etienne de Martel

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;
}
8
Mahmut EFE

Cette question est ancienne, mais je suis étonnée que personne ne mentionne boost::format:

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

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

La réponse suivante gère correctement les ints 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, fournissez des surcharges de cette fonction, une pour uint8_t et une pour int8_t, ou utilisez autre chose que "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 ints 8 bits comme je le pensais:

La réponse de Kornel Kisielewicz est excellente. Mais un léger ajout aide à attraper 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é cela pour ajouter un appel à std :: to_string car les types entiers de 8 bits (par exemple, les valeurs std::uint8_t passées) à std::stringstream sont traités comme des caractères, ce qui ne vous donne pas le résultat vouloir. Passer de tels entiers à std::to_string les traite correctement et ne fait pas de mal aux autres types d’entiers plus volumineux. Bien entendu, vous risquez de subir une légère baisse de performances dans ces cas, car l'appel std :: to_string n'est pas nécessaire.

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

4
Loss Mentality

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

Pour ceux d'entre vous qui ont compris que beaucoup/la plupart des ios::fmtflags ne fonctionnent pas avec std::stringstream mais ressemblent à l'idée de modèle que Kornel a postée il y a bien longtemps et qui 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);
2
Kevin

Jetez un coup d'œil sur ma solution,[1] que j’ai copié textuellement à partir de mon projet, un document en allemand est donc inclus dans la documentation relative à l’API. Mon objectif était de combiner flexibilité et sécurité dans le cadre de mes besoins actuels:[2]

  • no _0x_ préfixe ajouté: l'appelant peut décider
  • déduction automatique de la largeur : moins de frappe
  • contrôle explicite de largeur : élargissement pour le formatage, réduction (sans perte) pour gagner de la place
  • capable de traiter avec long long
  • restreint à types intégraux : éviter les surprises par 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"); 
_
2
Wolf

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

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

définition.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
0xfffffffffffffffffe

fe
fe fffffffe
fffffffffffffffe

1
Joma

Je fais:

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

Regardez SO réponse d'iFreilicht et le fichier d'en-tête de modèle requis à partir d'ici Gist !

1
CarpeDiemKopi