Número entero a cadena hexadecimal en C ++


127

¿Cómo convierto un entero en una cadena hexadecimal en C ++ ?

Puedo encontrar algunas formas de hacerlo, pero en su mayoría parecen dirigidas a C. No parece que haya una forma nativa de hacerlo en C ++. Sin embargo, es un problema bastante simple; Tengo uno intque me gustaría convertir en una cadena hexadecimal para imprimirlo más tarde.

Respuestas:


225

Use <iomanip>'s std::hex. Si imprime, simplemente envíelo a std::cout, si no, usestd::stringstream

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

Puedes anteponer el primero <<con << "0x"o lo que quieras si lo deseas.

Otros manuales de interés son std::oct(octal) ystd::dec (de vuelta al decimal).

Un problema que puede encontrar es el hecho de que esto produce la cantidad exacta de dígitos necesarios para representarlo. Puede usar setfilly setwesto para evitar el problema:

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

Finalmente, sugeriría tal función:

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

77
@MSalters: todo lo contrario. Pruebe su sugerencia sobre el inttipo;)
Kornel Kisielewicz

2
@LexFridman, para emitir exactamente la cantidad de dígitos hexadecimales según sea necesario. ¿Por qué emitir 8 dígitos si el tipo es uint8_t?
Kornel Kisielewicz

15
WARNIG: esto no funcionará para un solo byte porque char siempre se trata como char
ov7a

55
También requiere #include <sstream>
David Gausmann

2
Si estoy Formateo de múltiples enteros, parece que std::setwlas necesidades a ser la salida a la corriente de todos los int, mientras que std::hex, std::setfill, std::uppercase, ... sólo tienen que ser enviados a la corriente de salida de una vez. Esto parece inconsistente?
wcochran

39

Para hacerlo más ligero y rápido, sugiero usar el relleno directo de una cuerda.

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

¿Funcionará para algún tipo? Me refiero también a double, float, uint8_t?
SR

@SR Funciona para tipos integrales, no para doubley float(y no para punteros)
Wolf

... una mezcla muy pragmática (pero válida) de C y C ++, no estoy seguro acerca de la velocidad ... para mi gusto , es un poco denso.
Wolf

Gracias, brillante respuesta. Traer una biblioteca de flujo 'solo' para hacer esto parece un desperdicio.
DeveloperChris

1
Esto imprime 0000FFFFpara 0xFFFF. Prefiero tener 0xFFFFcomo salida.
DrumM

24

Úselo std::stringstreampara convertir enteros en cadenas y sus manipuladores especiales para establecer la base. Por ejemplo así:

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

14

Simplemente imprímalo como un número hexadecimal:

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

8
Yo usaría std::cout<<std::hex<<i<<std::dec;, de lo contrario todos los enteros que se transmiten más adelante estarán en hexadecimal. No necesita hacer eso para las otras respuestas que usan stringstreamporque la secuencia se descarta después de usarse, pero coutvive para siempre.
Mark Lakata

8

Puedes probar lo siguiente. Esta funcionando...

#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 buena respuesta, pero cuidado, eso to_stringes parte del espacio stdde nombres en C ++ 11
Alex

@ Alex sí, es 2014 después de todo ... Dios no lo quiera, tendremos que comenzar a tratar con C ++ 14 pronto.
Alex

7

Esta pregunta es antigua, pero me sorprende por qué nadie mencionó 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

Gracias al comentario de Lincoln a continuación, he cambiado esta respuesta.

La siguiente respuesta maneja correctamente las entradas de 8 bits en tiempo de compilación. Sin embargo, requiere C ++ 17. Si no tiene C ++ 17, tendrá que hacer otra cosa (por ejemplo, proporcionar sobrecargas de esta función, una para uint8_t y otra para int8_t, o usar algo además de "if constexpr", tal vez 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();
}

Respuesta original que no maneja entradas de 8 bits correctamente como pensé que lo hizo:

La respuesta de Kornel Kisielewicz es genial. Pero una pequeña adición ayuda a detectar casos en los que está llamando a esta función con argumentos de plantilla que no tienen sentido (por ejemplo, flotante) o que darían lugar a errores de compilación desordenados (por ejemplo, tipo definido por el usuario).

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

He editado esto para agregar una llamada a std :: to_string porque los tipos enteros de 8 bits (por ejemplo, los std::uint8_tvalores pasados) std::stringstreamse tratan como char, lo que no le da el resultado que desea. Pasando esos enteros astd::to_string manejarlos correctamente y no daña las cosas cuando se usan otros tipos de enteros más grandes. Por supuesto, es posible que sufra un ligero impacto en el rendimiento en estos casos, ya que la llamada std :: to_string es innecesaria.

Nota: Hubiera agregado esto en un comentario a la respuesta original, pero no tengo el representante para comentar.


en mis pruebas std :: to_string (i) no imprime std :: uint8_t enteros como hexadecimales. Creo que esto debe tener condiciones separadas para los tipos uint8_t e int8_t, ya que deben convertirse a enteros más grandes.
Lincoln

1
@ Lincoln Tienes razón. No sé qué estaba haciendo en ese momento (hace meses) que me hizo pensar que to_string manejaba entradas de 8 bits. Incluso volví a la versión del compilador que creo que estaba usando en ese entonces, solo para verificar, pero to_string no funcionó como dije. Entonces, ¿quién sabe? De todos modos, gracias por entender esto: he editado la respuesta a algo que debería funcionar correctamente.
Mentalidad de pérdida

1
Esto seguirá funcionando inesperadamente para char(que es distinto de ambos uint8_ty int8_ten la mayoría de las implementaciones (donde están respectivamente unsigned chary signed char)).
Ruslan

@ruslan Sí, también los tipos bool y wide char coinciden con std :: is_integral y no fallarán en la afirmación. Pero dado que char es, según el estándar, un tipo único garantizado, al igual que los tipos de caracteres anchos, puede manejarlos todos si lo desea (las excepciones son char sin signo / firmado, que coinciden con el tipo integral sin signo / firmado de cualquier ancho el byte está en la máquina actual, generalmente int8, por lo que no se puede filtrar si también quiere igualar entradas del mismo ancho). Puede rechazar char, caracteres anchos, bools agregando más términos al static_assert: ... && !std::is_same_v<char, T> && !std::is_same_v<bool, T>etc ...
Pérdida mental el

2

Para aquellos de ustedes que descubrieron que muchos / la mayoría de ellos ios::fmtflagsno funcionan con std::stringstreamla idea de plantilla que Kornel publicó cuando, lo siguiente funciona y es relativamente limpio:

#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
¿No deberías devolver buf.str ()?
ruipacheco

2

Hago:

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

Eche un vistazo a la respuesta SO de iFreilicht y el archivo de encabezado de plantilla requerido desde aquí ¡ GIST !


2

Solo eche un vistazo a mi solución, [1] que copié textualmente de mi proyecto, por lo que hay un documento API alemán incluido. Mi objetivo era combinar flexibilidad y seguridad dentro de mis necesidades reales: [2]

  • sin 0xprefijo agregado: la persona que llama puede decidir
  • deducción automática de ancho : menos tipeo
  • control de ancho explícito : ampliación para formateo, reducción (sin pérdida) para ahorrar espacio
  • capaz de lidiar con long long
  • restringido a tipos integrales : evite sorpresas por conversiones silenciosas
  • facilidad de comprensión
  • sin límite codificado
#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] basado en la respuesta de Kornel Kisielewicz
[2] Traducido al lenguaje de CppTest , así es como se lee:

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
Podría mostrar la deducción de ancho con, por ejemplo,TEST_ASSERT(int_to_hex(short(0x12)) == "0012");
Carreras de ligereza en órbita el

2

Código para su referencia:

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

44
Esto realmente no se suma a las respuestas existentes, y no tiene sentido explícitamente clearel sstream(será destruido cuando la función regrese en la siguiente línea de todos modos). Puede evitar el nombre por hexStrcompleto y solo return sstream.str();sin clearing y obtener el mismo efecto, reduciendo cuatro líneas de código a una.
ShadowRanger

1
cuando el propósito del foro es comprender las cosas y el uso. ser detallado es mucho mejor para proporcionar una imagen clara, que guardar líneas. la pregunta no estaba en el código optimizado, y la respuesta intenta dar una forma de método modular para tratar tales conversiones. @ShadowRanger
parásito

1
¿Para qué sirve sstream.clear();? El sstreamobjeto se destruye automáticamente al final del alcance, por return sstream.str();lo que lo haría.
Wolf

sstream.clearsolo borrará el contenido, antes de que la secuencia termine con el final del alcance (para borrar cualquier error y marcas de eof con clear). De hecho, cuando el alcance muere, con la vida útil de la variable de flujo, y por sstream.strlo tanto, se puede utilizar para devolver por valor. [Referencia: cplusplus.com/reference/ios/ios/clear/]
parasrish el

2

Mi solución. Solo se permiten tipos integrales.

Actualizar. Puede establecer el prefijo opcional 0x en el segundo parámetro.

definición.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;
}

Resultados:
0xfe
0xfe
0xfffffffe
0xfffffffffffffffe

fe
fe fffffffe
fffffffffffffffe


1

Me gustaría agregar una respuesta para disfrutar de la belleza del lenguaje C ++. Su adaptabilidad para trabajar en niveles altos y bajos. Feliz programación

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

Ejemplos:

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"

Esto utiliza algunas técnicas que no se ven en las otras respuestas. ¿Puede editar la respuesta para incluir alguna explicación de cómo y por qué funciona?
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;

Usando puntero vacío:

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

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

Salidas:

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 (dirección)
6946500 (dirección a dec)
0x69fec4 (dirección a dec, salida en hexadecimal)


instintivamente fue con esto ...
int address = (int) & var;

vi esto en otro lado ...
unsigned long address = reinterpret_cast (& var);

el comentario me dijo que esto es correcto ...
int address = (int) & var;

hablando de ligereza bien cubierta , ¿dónde estás? ¡están recibiendo demasiados me gusta!


Esta pregunta ya ha sido bien cubierta; ¿Qué agrega su respuesta a las ya publicadas? ¿Y qué tienen que ver las direcciones con él?
ligereza corre en órbita el

@LightnessRacesinOrbit no se ha cerrado, ¿verdad? ¿Le dijiste eso a los últimos 3 chicos que comentaron? esto solo llega más al punto de lo que estaba buscando. Podría ayudar a alguien más. ¿Y qué tienen que ver las direcciones? ¿Quién lee las direcciones en decimal? Es un ejemplo real.
Charco

Publicar la misma respuesta que ya se publicó hace casi nueve años no se considera útil, y esta introducción de punteros a la ecuación parece haber salido de la nada: el OP no pregunta sobre los punteros. Además, no, no seríaunsigned long sino std::intptr_t.
Carreras de ligereza en órbita

intptr_t = int ... uintptr_t = unsigned int ... ¿las direcciones de memoria están firmadas ahora? ¿Y cuánta memoria te da un int?
Charco

Te estás perdiendo el punto. Un intptr_tpuede almacenar cualquier puntero en la plataforma de compilación; eso no es [necesariamente] cierto de unsigned int. Y, de nuevo, nada de esto es relevante para la pregunta. No hay más respuestas de mi parte
ligereza corre en órbita el
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.