Целое число в шестнадцатеричную строку в C ++

128

Как преобразовать целое число в шестнадцатеричную строку в C ++ ?

Я могу найти несколько способов сделать это, но они в основном ориентированы на C. Не похоже, что есть собственный способ сделать это в C ++. Однако это довольно простая проблема; У меня есть intстрока, которую я хотел бы преобразовать в шестнадцатеричную строку для последующей печати.

kryptobs2000
источник

Ответы:

226

Используйте <iomanip>s std::hex. Если вы печатаете, просто отправьте его std::cout, если нет, то используйтеstd::stringstream

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

Вы можете предварять первый <<с << "0x"или что угодно , если вы хотите.

Другие интересующие нас манипуляции - это std::oct(восьмеричное) и std::dec(обратно десятичное).

Одна из проблем, с которой вы можете столкнуться, заключается в том, что это дает точное количество цифр, необходимое для его представления. Вы можете использовать setfillи setwэто, чтобы обойти проблему:

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

Наконец, я бы предложил такую ​​функцию:

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 - совсем наоборот. Проверьте свое предложение по intтипу;)
Kornel Kisielewicz
2
@LexFridman, чтобы выдать ровно необходимое количество шестнадцатеричных цифр. Зачем выдавать 8 цифр, если тип uint8_t?
Kornel Kisielewicz
16
ПРЕДУПРЕЖДЕНИЕ: это не сработает для однобайтного байта, потому что char всегда обрабатывается как char
ov7a
5
Вам также потребуется #include <sstream>
Дэвид Гаусманн,
2
Если я форматирование несколько Интса, кажется , что std::setwдолжно быть выход для потока для каждых межд, в то время как std::hex, std::setfill, std::uppercase, ... нужно только быть отправлены в выходном поток раза. Это кажется непоследовательным?
wcochran
39

Чтобы было легче и быстрее, предлагаю использовать прямое заполнение строки.

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;
}
АндрейС Щербаков
источник
Подойдет ли это для любого типа? Я имею в виду также double, float, uint8_t?
SR
@SR Он работает для целочисленных типов, а не для doubleи float(и не для указателей)
Wolf
... очень прагматичное (но действительное) сочетание C и C ++, я не уверен в скорости ... на мой вкус , это немного плотно.
Wolf
Спасибо, прекрасный ответ. Использование потоковой библиотеки «просто» для этого кажется пустой тратой.
РазработчикChris
1
Это печатает 0000FFFFдля 0xFFFF. Я предпочитаю иметь 0xFFFFкак результат.
DrumM
24

Используется std::stringstreamдля преобразования целых чисел в строки и специальных манипуляторов для установки базы. Например так:

std::stringstream sstream;
sstream << std::hex << my_integer;
std::string result = sstream.str();
phlipsy
источник
14

Просто распечатайте его как шестнадцатеричное число:

int i = /* ... */;
std::cout << std::hex << i;
Этьен де Мартель
источник
8
Я бы использовал std::cout<<std::hex<<i<<std::dec;, иначе все целые числа, которые передаются позже, будут в шестнадцатеричном формате. Вам не нужно делать это для других ответов, которые используются, stringstreamпотому что поток отбрасывается после использования, но coutживет вечно.
Марк Лаката
8

Вы можете попробовать следующее. Это работает...

#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
хороший ответ, но будьте осторожны, to_stringэто часть пространства имен stdв C ++ 11
Alex
@Alex да, все-таки 2014 год ... не дай бог, скоро нам придется заняться C ++ 14.
Alex
7

Это старый вопрос, но я удивлен, почему никто не упомянул boost::format:

cout << (boost::format("%x") % 1234).str();  // output is: 4d2
s4eed
источник
4
int num = 30;
std::cout << std::hex << num << endl; // This should give you hexa- decimal of 30
Махеш
источник
4

Благодаря приведенному ниже комментарию Линкольна я изменил этот ответ.

Следующий ответ правильно обрабатывает 8-битные int во время компиляции. Однако для этого требуется C ++ 17. Если у вас нет C ++ 17, вам придется сделать что-то еще (например, предоставить перегрузки этой функции, одну для uint8_t и одну для int8_t, или использовать что-то помимо «if constexpr», возможно, 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();
}

Исходный ответ, который не обрабатывает 8-битные целые числа правильно, как я думал:

Ответ Корнеля Киселевича великолепен. Но небольшое дополнение помогает поймать случаи, когда вы вызываете эту функцию с аргументами шаблона, которые не имеют смысла (например, с плавающей точкой) или которые могут привести к беспорядочным ошибкам компилятора (например, определяемого пользователем типа).

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

Я отредактировал это, чтобы добавить вызов std :: to_string, потому что 8-битные целые типы (например, std::uint8_tпередаваемые значения) std::stringstreamобрабатываются как char, что не дает желаемого результата. Передача таких целых чисел для std::to_stringих правильной обработки и не повредит при использовании других, более крупных целочисленных типов. Конечно, в этих случаях возможно небольшое снижение производительности, поскольку вызов std :: to_string не нужен.

Примечание: я бы просто добавил это в комментарий к исходному ответу, но у меня нет представителя для комментариев.

Потеря психики
источник
в моем тестировании std :: to_string (i) не печатает целые числа std :: uint8_t как шестнадцатеричные. Я думаю, что здесь, возможно, должны быть отдельные условия для типов uint8_t и int8_t, поскольку они должны быть приведены к большим целым числам.
Линкольн
1
@Lincoln Вы правы. Я не знаю, что я делал в то время (несколько месяцев назад), что заставило меня to_string обрабатывать 8-битные целые числа. Я даже вернулся к версии компилятора, которую, как мне кажется, использовал тогда, просто для двойной проверки, но to_string не сработал, как я сказал. Так кто знает? В любом случае, спасибо, что уловили это - я отредактировал ответ на то, что должно работать правильно.
Loss Mentality
1
Это по-прежнему будет неожиданно работать для char(что отличается от обоих uint8_tи int8_tв большинстве реализаций (где они соответственно unsigned charи signed char)).
Руслан
@ruslan Да, также типы bool и wide char соответствуют std :: is_integral и не приведут к ошибке assert. Но поскольку char, согласно std., Является гарантированным уникальным типом, как и широкие типы char, при желании вы можете обрабатывать их все (исключение составляют un / signed char, которые соответствуют интегральному типу un / signed любой ширины a byte находится на текущей машине - обычно это int8 - и поэтому не может быть отфильтрован, если вы также хотите сопоставить int одинаковой ширины). Вы можете отклонить char, широкие символы, bools, добавив дополнительные термины в static_assert: ... && !std::is_same_v<char, T> && !std::is_same_v<bool, T>etc ...
Loss Mentality
2

Для тех из вас, кто понял, что многие / большинство из них ios::fmtflagsеще не работают, std::stringstreamкак идея шаблона, которую Kornel опубликовал еще тогда, следующее работает и относительно чистое:

#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
источник
9
Разве вы не должны просто вернуть buf.str ()?
ruipacheco
2

Я делаю:

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

Взгляните на SO- ответ от iFreilicht и требуемый заголовочный файл шаблона отсюда GIST !

CarpeDiemKopi
источник
2

Просто взгляните на мое решение [1], которое я дословно скопировал из моего проекта, так что там есть немецкий документ API. Моей целью было объединить гибкость и безопасность в рамках моих реальных потребностей: [2]

  • нет 0xпрефикса добавил: вызывающий абонент может принять решение
  • автоматическое уменьшение ширины : меньше набора текста
  • явный контроль ширины : расширение для форматирования, (без потерь) сжатие для экономии места
  • способен справиться с long long
  • ограничены целочисленными типами : избегайте неожиданностей с помощью тихих преобразований
  • легкость понимания
  • без жесткого ограничения
#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] на основе ответа Корнеля Киселевича
[2] В переводе на язык CppTest он выглядит следующим образом:

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
Могу продемонстрировать уменьшение ширины, например,TEST_ASSERT(int_to_hex(short(0x12)) == "0012");
Гонки
2

Код для справки:

#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;
}
parasrish
источник
4
Это на самом деле не добавить к существующим ответам, и это бессмысленно явно (он будет уничтожен , когда функция возвращает на следующей строке в любом случае). Вы могли бы избежать именованный целиком и просто без ING и получить тот же эффект, уменьшая четыре строки кода в один. clearsstreamhexStrreturn sstream.str();clear
ShadowRanger
1
когда целью форума является понимание вещей и использования. многословие гораздо лучше для получения четкой картины, чем сохранение строк. вопрос не касался оптимизированного кода, и в ответе предпринимается попытка дать модульный метод работы с такими преобразованиями. @ShadowRanger
parasrish
1
В чем цель sstream.clear();? sstreamОбъект автоматически уничтожается в конце области, так что return sstream.str();это сделает.
Wolf
sstream.clearпросто очистит содержимое до того, как поток закончится концом области (чтобы очистить все флаги fail и eof с помощью clear). Действительно, когда область видимости умирает, с продолжительностью жизни переменной потока и, следовательно, sstream.strможет использоваться для возврата по значению. [Ссылка: cplusplus.com/reference/ios/ios/clear/]
parasrish
2

Мое решение. Допускаются только целые типы.

Обновить. Вы можете установить необязательный префикс 0x во втором параметре.

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

Результаты:
0xfe
0xfe
0xfffffffe
0xfffffffffffffffe

fe
fe fffffffe
fffffffffffffffe

Joma
источник
1

Я хотел бы добавить ответ, чтобы насладиться красотой языка C ++. Его приспособляемость к работе на высоких и низких уровнях. Удачного программирования.

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

Примеры:

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
источник
При этом используются некоторые методы, которых не было в других ответах. Не могли бы вы отредактировать ответ, включив в него некоторые пояснения, как и почему это работает?
Джейсон Аллер,
0
#include <iostream> 
#include <sstream>  

int main()
{
unsigned int i = 4967295; // random number
std::string str1, str2;
unsigned int u1, u2;

std::stringstream ss;

Использование указателя 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();

Добавление 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();

Выходы:

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 (адрес)
6946500 (адрес для dec)
0x69fec4 (адрес для dec, вывод в шестнадцатеричном формате)


инстинктивно пошел с этим ...
int address = (int) & var;

видел это в другом месте ...
длинный адрес без знака = reinterpret_cast (& var);

комментарий сказал мне, что это правильно ...
int address = (int) & var;

Говоря о хорошо скрытой легкости, где ты? они получают слишком много лайков!

лужа
источник
Этот вопрос уже хорошо освещен; что ваш ответ добавляет к уже опубликованным? И при чем тут адреса?
Гонки за легкостью на орбите
@LightnessRacesinOrbit он еще не был закрыт? ты сказал это последним 3 парням, которые комментировали? это просто ближе к сути того, что я искал. это может помочь кому-то другому. и при чем тут адреса? кто читает адреса в десятичном виде? это реальный пример.
Puddle
Публикация того же ответа, который уже был опубликован почти девять лет назад, считается бесполезной, и это введение указателей в уравнение, похоже, возникло неожиданно - OP не спрашивает об указателях. Более того, нет, не было бы « unsigned longно» std::intptr_t.
Гонки за легкостью на орбите
intptr_t = int ... uintptr_t = unsigned int ... подписаны ли адреса памяти? а сколько памяти дает int?
Puddle
Вы упускаете суть. intptr_tМожет хранить любой указатель на платформе сборки; это не [обязательно] верно unsigned int. И, опять же, все это не имеет отношения к вопросу. Никаких дальнейших ответов от меня
Lightness Races in Orbit