Número inteiro para hexadecimal em C ++

127

Como converter um número inteiro em uma sequência hexadecimal em C ++ ?

Posso encontrar algumas maneiras de fazer isso, mas elas parecem direcionadas para C. Parece que não há uma maneira nativa de fazer isso em C ++. É um problema bastante simples; Eu tenho um intque gostaria de converter em uma sequência hexadecimal para impressão posterior.

kryptobs2000
fonte

Respostas:

225

Use <iomanip>'s std::hex. Se você imprimir, basta enviá-lo para std::cout, caso contrário, usestd::stringstream

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

Você pode anexar o primeiro <<com << "0x"ou o que quiser, se desejar.

Outras manips de interesse são std::oct(octal) e std::dec(de volta ao decimal).

Um problema que você pode encontrar é o fato de que isso produz a quantidade exata de dígitos necessários para representá-lo. Você pode usar setfille setwisso para contornar o problema:

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

Então, finalmente, sugiro uma função:

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
fonte
7
@MSalters - muito pelo contrário. Teste a sua sugestão sobre o inttipo;)
kornel kisielewicz
2
@ LexFridman, para emitir exatamente a quantidade de dígitos hexadecimais, conforme necessário. Por que emitir 8 dígitos se o tipo é um uint8_t?
Kornel Kisielewicz
15
Warnig: isto não vai funcionar para um único byte, porque char é sempre threated como char
ov7a
5
Você também exigem #include <sstream>
David Gausmann
2
Se estou formatação múltiplas ints, Parece que std::setwprecisa ser saída para o fluxo para cada int, enquanto std::hex, std::setfill, std::uppercase, ... só precisa ser enviado para o fluxo de saída uma vez. Isso parece inconsistente?
Wcochran
39

Para torná-lo mais leve e rápido, sugiro usar o preenchimento direto de uma corda.

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
fonte
Isso funcionará para qualquer tipo? Quero dizer também double, float, uint8_t?
SR
@SR Ele funciona para tipos integrais, não para doublee float(e não para ponteiros)
Lobo
... uma mistura muito pragmática (mas válida) de C e C ++, não tenho certeza sobre velocidade ... para o meu gosto , é um pouco denso.
6262 Wolf
Obrigado, resposta brilhante. Trazer uma biblioteca de fluxo 'apenas' para fazer isso parece um desperdício.
DeveloperChris
1
Isso imprime 0000FFFFpara 0xFFFF. Eu prefiro ter 0xFFFFcomo saída.
DrumM
24

Use std::stringstreampara converter números inteiros em strings e seus manipuladores especiais para definir a base. Por exemplo, assim:

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

Basta imprimi-lo como um número hexadecimal:

int i = /* ... */;
std::cout << std::hex << i;
Etienne de Martel
fonte
8
Eu usaria std::cout<<std::hex<<i<<std::dec;, caso contrário, todos os números inteiros que serão transmitidos posteriormente serão em hexadecimal. Você não precisa fazer isso para as outras respostas que usam stringstreamporque o fluxo é descartado após ser usado, mas coutvive para sempre.
precisa saber é o seguinte
8

Você pode tentar o seguinte. Está 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;
}
Mahmut EFE
fonte
1
uma resposta agradável, mas cuidado que to_stringé parte do namespace stdem C ++ 11
Alex
@ Alex, sim, é 2014, afinal ... o céu nos livre será que começaremos a lidar com o C ++ 14 em breve.
22414 Alex
7

Esta pergunta é antiga, mas estou surpreso por que ninguém mencionou boost::format:

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

Graças ao comentário de Lincoln abaixo, alterei esta resposta.

A resposta a seguir lida corretamente com entradas de 8 bits em tempo de compilação. No entanto, eles exigem C ++ 17. Se você não possui C ++ 17, precisará fazer outra coisa (por exemplo, fornecer sobrecargas dessa função, uma para uint8_t e outra para int8_t, ou usar algo além de "if constexpr", talvez 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();
}

Resposta original que não lida com ints de 8 bits corretamente como eu pensava:

A resposta de Kornel Kisielewicz é ótima. Porém, um pequeno acréscimo ajuda a capturar casos em que você está chamando essa função com argumentos de modelo que não fazem sentido (por exemplo, flutuação) ou que resultariam em erros confusos do compilador (por exemplo, tipo definido pelo usuário).

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

Eu editei isso para adicionar uma chamada para std :: to_string porque os tipos inteiros de 8 bits (por exemplo, std::uint8_tvalores passados) std::stringstreamsão tratados como char, o que não fornece o resultado desejado. Passar esses números inteiros para std::to_stringmanipulá-los corretamente e não prejudica as coisas ao usar outros tipos inteiros maiores. É claro que você pode sofrer um leve impacto no desempenho nesses casos, pois a chamada std :: to_string é desnecessária.

Nota: eu teria acabado de adicionar isso em um comentário à resposta original, mas não tenho o representante para comentar.

Mentalidade de perda
fonte
no meu teste std :: to_string (i) não imprime números inteiros std :: uint8_t como hexadecimal. Eu acho que isso pode ter que ter condições separadas para os tipos uint8_t e int8_t, pois eles precisam ser convertidos para números inteiros maiores.
Lincoln
1
@ Lincoln Você está certo. Não sei o que estava fazendo na época (meses atrás) que me levou a lidar com ints de 8 bits. Eu até voltei para a versão do compilador que eu estava usando naquela época, apenas para verificar novamente, mas o to_string não funcionou como eu disse. Então quem sabe? De qualquer forma, obrigado por entender isso - editei a resposta para algo que deve funcionar corretamente.
precisa
1
Isso ainda funcionará inesperadamente para char(que é diferente da maioria uint8_te int8_tna maioria das implementações (onde elas são respectivamente unsigned chare signed char)).
Ruslan
@ruslan Sim, também os tipos bool e wide char correspondem a std :: is_integral e não falharão na afirmação. Porém, como char é, por padrão, um tipo exclusivo garantido, assim como os tipos de caracteres amplos, você pode manipular todos eles, se desejar (as exceções são char não assinado / que corresponde ao tipo integral não assinado de qualquer largura que O byte está na máquina atual - normalmente int8 - e, portanto, não pode ser filtrado se você quiser combinar ints da mesma largura também). Você pode rejeitar char, wide chars, bools adicionando mais termos ao static_assert: ... && !std::is_same_v<char, T> && !std::is_same_v<bool, T>etc ...
Loss Mentality
2

Para aqueles de vocês que descobriram que muitos / a maioria ios::fmtflagsainda não trabalha std::stringstreamcomo a ideia de modelo que Kornel postou quando, o seguinte funciona e é relativamente limpo:

#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
fonte
9
Você não deveria simplesmente retornar buf.str ()?
Ruipacheco 12/10
2

Eu faço:

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

Dê uma olhada na resposta SO da iFreilicht e no arquivo de cabeçalho do modelo necessário a partir daqui GIST !

CarpeDiemKopi
fonte
2

Basta dar uma olhada na minha solução, [1] que eu copiei literalmente do meu projeto, para que haja um documento de API em alemão incluído. Meu objetivo era combinar flexibilidade e segurança às minhas necessidades reais: [2]

  • nenhum 0xprefixo adicionado: o chamador pode decidir
  • dedução automática da largura : menos digitação
  • controle explícito de largura : ampliando para formatação, (sem perdas) diminuindo para economizar espaço
  • capaz de lidar com long long
  • restrito a tipos integrais : evite surpresas por conversões silenciosas
  • facilidade de entendimento
  • sem limite 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] Com base na resposta de Kornel Kisielewicz.
[2] Traduzido para o idioma do CppTest , é assim que se lê:

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"); 
Lobo
fonte
1
Poderia mostrar a dedução de largura com, por exemplo,TEST_ASSERT(int_to_hex(short(0x12)) == "0012");
Lightness Races in Orbit
2

Código para sua referência:

#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;
}
parasita
fonte
4
Isso realmente não contribui para as respostas existentes, e não faz sentido explicitamente clearas sstream(elas serão destruídas quando a função retornar na próxima linha de qualquer maneira). Você pode evitar o nome hexStrcompletamente e apenas return sstream.str();sem clearing e obter o mesmo efeito, reduzindo quatro linhas de código para uma.
ShadowRanger
1
quando o objetivo do fórum é entender as coisas e o uso. ser detalhado é muito melhor fornecer uma imagem clara do que salvar linhas. A pergunta não estava no código otimizado e a resposta tenta oferecer uma maneira modular de lidar com essas conversões. @ShadowRanger
parasrish 19/02
1
Qual é o propósito sstream.clear();? O sstreamobjeto é destruído automaticamente no final do escopo, e o return sstream.str();faria.
Wolf
sstream.clearapenas limpará o conteúdo antes que o fluxo termine com o escopo final (para limpar qualquer falha e sinalizadores de eof com limpeza). De fato, quando o escopo morre, com a vida útil da variável de fluxo e, portanto, sstream.strpode ser usado para retornar por valor. [Referência: cplusplus.com/reference/ios/ios/clear/]
parasrish
2

Minha solução Somente tipos integrais são permitidos.

Atualizar. Você pode definir o prefixo opcional 0x no segundo parâmetro.

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

Resultados:
0xfe
0xfe
0xfffffffe
0xfffffffffffffffe

fe
fe fffffffe
fffffffffffffffe

Joma
fonte
1

Gostaria de adicionar uma resposta para apreciar a beleza da linguagem C ++. Sua adaptabilidade para trabalhar em níveis altos e baixos. Feliz programação.

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

Exemplos:

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
fonte
Isso usa algumas técnicas não vistas nas outras respostas. Você pode editar a resposta para incluir uma explicação de como e por que ela 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 ponteiro nulo:

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

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

Saídas:

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
fonte
-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 (endereço)
6946500 (endereço para dec)
0x69fec4 (endereço para dec, saída em hexadecimal)


instintivamente foi com isso ...
int address = (int) & var;

vi isso em outro lugar ...
endereço longo não assinado = reinterpret_cast (& var);

o comentário me disse que isso está correto ...
int address = (int) & var;

falando de leveza bem coberta , onde você está? eles estão recebendo muitos gostos!

Poça
fonte
Esta questão já foi bem abordada; o que sua resposta adiciona àquelas já postadas? E o que os endereços têm a ver com isso?
Lightness Races em órbita
@LightnessRacesinOrbit não foi fechado, pois não? você disse isso para os 3 últimos caras que comentaram? isso só vai mais ao ponto do que eu estava procurando. isso pode ajudar outra pessoa. e o que os endereços têm a ver com isso? quem lê endereços em decimal? é um exemplo real.
Puddle
A publicação da mesma resposta que já foi publicada há quase nove anos não é considerada útil, e esta introdução de indicadores para a equação parece ter surgido do nada - o OP não pergunta sobre indicadores. Além disso, não, não seria unsigned longmas std::intptr_t.
Lightness Races em órbita
intptr_t = int ... uintptr_t = unsigned int ... os endereços de memória estão assinados agora? e quanta memória um int lhe dá?
Puddle
Você está perdendo o ponto. Um intptr_tpode armazenar qualquer ponteiro na plataforma de construção; isso não é [necessariamente] verdadeiro unsigned int. E, novamente, nada disso é relevante para a questão. Sem respostas adicionais de mim
Lightness Races in Orbit