Цілий шістнадцятковий рядок у C ++


127

Як перетворити ціле число в шістнадцятковий рядок у C ++ ?

Я можу знайти деякі способи це зробити, але вони, як правило, орієнтовані на C. Це не здається, що це є рідним способом зробити це на C ++. Це досить проста проблема; У мене є переклад, intякий я хотів би перетворити на шістнадцятковий рядок для подальшого друку.

Відповіді:


225

Використовуйте <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

15
ПОПЕРЕДЖЕННЯ: це не буде працювати для одного байту, оскільки 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(а не для покажчиків)
Вовк

... дуже прагматична (але дійсна) суміш C і C ++, я не впевнений у швидкості ... на мій смак , вона трохи щільна.
Вовк

Дякую, блискуча відповідь. Приведення в бібліотеку потоків "просто" для цього видається такою марною.
DeveloperChris

1
Це друкує 0000FFFFдля 0xFFFF. Я вважаю за краще мати 0xFFFFвихід.
DrumM

24

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

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

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.
Олексій

7

Це питання давнє, але я здивований, чому ніхто не згадав boost::format:

cout << (boost::format("%x") % 1234).str();  // output is: 4d2


4

Завдяки коментарю Лінкольна нижче, я змінив цю відповідь.

Наступна відповідь належним чином обробляє 8-бітові вставки під час компіляції. Однак, це вимагає C ++ 17. Якщо у вас немає C ++ 17, вам доведеться зробити щось інше (наприклад, забезпечити перевантаження цієї функції, одну для uint8_t і одну для int8_t, або використовувати щось окрім "якщо 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-бітові вставки правильно, як я вважав:

Відповідь Корнеля Кіселевича чудова. Але невелике доповнення допомагає зафіксувати випадки, коли ви викликаєте цю функцію за допомогою аргументів шаблону, які не мають сенсу (наприклад, float), або це призведе до брудних помилок компілятора (наприклад, визначеного користувачем типу).

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 Ви праві. Я не знаю, що я робив у той час (зараз місяці тому), що змусило мене з цим режимом обробляти 8-бітні ints. Я навіть повернувся до версії компілятора, я думаю, що я використовував тоді, лише для подвійної перевірки, але to_string не працював, як я сказав, що це робив. То хто знає? У будь-якому випадку, дякую, що ви зрозуміли це - я відредагував відповідь на те, що повинно працювати правильно.
менталітет втрати

1
Це все одно буде працювати несподівано для char(що відрізняється від обох uint8_tта int8_tв більшості реалізацій (де вони відповідно unsigned charі signed char).
Руслан

@ruslan Так, також типи bool та широких знаків char відповідають std :: is_integral і не підведуть ствердження. Але оскільки char - відповідно до STD. - це гарантований унікальний тип, як і широкі типи char, за бажанням ви можете обробляти їх усіма (винятки - це un / підписаний char, який відповідає непідписаному інтегральному типу незалежно від ширини байт знаходиться на поточній машині - як правило, int8 - і тому не може бути відфільтрований, якщо ви також хочете відповідати точок з однаковою шириною). Ви можете відхилити char, широкі символи, bools, додавши більше термінів до static_assert: ... && !std::is_same_v<char, T> && !std::is_same_v<bool, T>тощо ...
менталітет втрати

2

Для тих із вас, хто з’ясував, що багато хто з них ios::fmtflagsще не працює, std::stringstreamяк ідея шаблону, яку Корнель опублікував назад, коли працює наступне:

#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
Ви не повинні просто повернути buf.str ()?
ruipacheco

2

Я згоден:

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

Подивіться на відповідь SO від iFreilicht та потрібний файл шапки заголовка звідси GIST !


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

4
Це насправді не додає до існуючих відповідей, і безглуздо явно clearце sstream(він буде зруйнований, коли функція повернеться в наступному рядку). Ви можете уникнути названих hexStrцілком і просто return sstream.str();без clearтого, щоб отримати той самий ефект, зводячи чотири рядки коду до одного.
ShadowRanger

1
коли мета форуму - зрозуміти речі та використання. бути багатослівним набагато краще, щоб забезпечити чітку картину, ніж збереження ліній. Питання було не в оптимізованому коді, а відповідь намагається дати модульно-метод способу поводження з такими перетвореннями. @ShadowRanger
парашутувати

1
Яка мета sstream.clear();? sstreamОб'єкт автоматично знищується в кінці області, так що return sstream.str();це зробить.
Вовк

sstream.clearпросто очистить вміст, перш ніж поток закінчиться діапазоном (щоб очистити будь-які провали та прапорці eof). Дійсно, коли область вмирає, з тривалістю життя потокової змінної, і тому sstream.strможна використовувати для повернення за значенням. [Довідка: cplusplus.com/reference/ios/ios/clear/]
парашутизм

2

Моє рішення. Дозволені лише цілісні типи.

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

визначення.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
0xfffffffffffffffffe

Fe
Fe FFFFFFFE
fffffffffffffffe


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"

Для цього використовуються одні методи, які не бачили в інших відповідях. Чи можете ви відредагувати відповідь, щоб включити пояснення, як і чому вона працює?
Джейсон Аллер

0
#include <iostream> 
#include <sstream>  

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

std::stringstream ss;

Використання недійсного вказівника:

// 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 (адреса в грудні)
0x69fec4 (адреса в грудні, вихід у шістнадцятковій формі)


інстинктивно пішов з цим ...
int address = (int) & var;

бачив це в іншому місці ...
неподписана довга адреса = reinterpret_cast (& var);

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

говорячи про добре охоплену легкість, де ти? вони отримують занадто багато лайків!


Це питання вже добре висвітлено; що ваша відповідь додає до тих, хто вже опублікував? І які стосунки стосуються цього?
Гонки легкості на орбіті

@LightnessRacesinOrbit це не закрито, чи не так? ви це сказали останнім трьом хлопцям, які коментували? це просто стає більше до того, що я шукав. це може допомогти комусь іншому. і які стосунки стосуються цього? хто читає адреси десятковою? це справжній приклад.
Калюжа

Опублікування тієї самої відповіді, яка вже була розміщена майже дев'ять років тому, не вважається корисною, і це введення покажчиків до рівняння, схоже, вийшло невдало - ОП не запитує про покажчики. Чи не Крім того, немає, це не було б , unsigned longале std::intptr_t.
Гонки легкості на орбіті

intptr_t = int ... uintptr_t = неподписаний int ... чи підписані адреси пам'яті зараз? і скільки пам’яті надає інт?
Калюжа

Ви пропускаєте суть. Anintptr_t може зберігати будь-який вказівник на платформі збірки; це не обов'язково правда unsigned int. І, знову ж таки, нічого з цього питання не стосується. Більше ніяких відповідей від мене
Гонки легкості в орбіті
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.