Как я могу напечатать 0x0a вместо 0xa с помощью cout?

Как я могу напечатать 0x0a вместо 0xa, используя cout?

#include  <iostream>

using std::cout;  
using std::endl;  
using std::hex;

int main()  
{  
    cout << hex << showbase << 10 << endl;  
}

person Ayrosa    schedule 22.04.2011    source источник
comment
Каковы именно ваши требования. В заголовке указано 0x0a, в теле вашего вопроса указано 0x0A. В любом случае явное std::cout << "0x0a" или std::cout << "0x0A" могло бы соответствовать вашим требованиям, но я предполагаю, что вы действительно хотите отформатировать число. Как вы хотите отформатировать (например) 16, 255, 256, 65536, -1?   -  person CB Bailey    schedule 23.04.2011
comment
@Charles Вопрос заключался в том, как напечатать 0 после x и перед A или a, если на то пошло. Как вы можете убедиться, первый ответ неверен, поскольку он все еще печатает 0xa (0xA, если используется верхний регистр). Но в любом случае вопрос уже отмечен как отвеченный.   -  person Ayrosa    schedule 23.04.2011
comment
Но зачем лишний 0? Вы всегда хотите 0x0 или вам нужна минимальная длина строки?   -  person CB Bailey    schedule 23.04.2011
comment
Если шестнадцатеричное число 0xA, мне нужно 0x0A. Если число 0x123, я хочу, чтобы это было 0x0123 и т.д., то есть четное число шестнадцатеричных цифр.   -  person Ayrosa    schedule 23.04.2011
comment
Не думаю, что вы поняли, к чему я клоню. Вы точно указали, как должно появиться 10, но как насчет 1–9 и 11–15? А как насчет 256? Вы хотите 0x0a, потому что вам нужна минимальная ширина или потому что вам всегда нужен ведущий ноль? Если вы точно не со своей спецификацией, вы можете не получить желаемых ответов.   -  person CB Bailey    schedule 23.04.2011


Ответы (8)


Это работает для меня в GCC:

#include  <iostream>
#include  <iomanip>

using namespace std;

int main()
{
    cout << "0x" << setfill('0') << setw(2) << right << hex << 10 << endl;
}

Если вам надоело странное форматирование iostream, дайте Boost.Format попробуйте. Он позволяет использовать старые добрые спецификаторы формата в стиле printf, но при этом является типобезопасным.

#include <iostream>
#include <boost/format.hpp>

int main()
{
    std::cout << boost::format("0x%02x\n") % 10;
}

ОБНОВЛЕНИЕ (2019 г.)

Ознакомьтесь с принятой {fmt} библиотекой в C ++ 20. Тесты показывают, что он быстрее, чем Boost.Format.

#if __has_include(<format>)
    #include <format>
    using std::format;
#else
    #include <fmt/format.h>
    using fmt::format;
#endif

std::cout << format("{:#04x}\n", 10);
person Emile Cormier    schedule 22.04.2011
comment
Это неверный ответ. Если кто-то делал cout << left << whatever раньше, вы получите плохой результат из-за постоянного левого / правого iomanip. Он должен быть setfill('0') << setw(2) << right << hex, чтобы всегда гарантировать правильное выравнивание. - person fuujuhi; 16.12.2019
comment
@fuujuhi Неправильно? Это довольно жестко. Я бы сказал, что он неполный. Тем не менее, спасибо за предложение. - person Emile Cormier; 17.12.2019
comment
@EmileCornier Извини, я не хотел быть резким. Действительно, неполный, но, к сожалению, может привести к неприятным ошибкам. В последнее время в моем коде были две ошибки из-за постоянного iomanip (полное раскрытие: раньше я много кодировал на C ++, но не сейчас), и это заставило меня подумать, что C ++ iostream ужасно ошибочен. Для современного языка iostream превращает печать простейших вещей в кошмар. Вы думаете, что печатаете целое число, но на самом деле вы печатаете его в шестнадцатеричном формате. Или вы получите 0x90 на выходе, но на самом деле значение равно 0x09. - person fuujuhi; 19.12.2019

Используйте setw и setfill из iomanip

#include  <iostream>
#include  <iomanip>

using std::cout;  
using std::endl;  
using std::hex;

int main()
{
    cout << "0x" << std::setfill('0') << std::setw(2) << hex << 10 << endl;
}

Лично меня всегда раздражает статическая природа iostreams. Я думаю, что формат ускорения - лучший вариант, поэтому я рекомендовал бы другой ответ.

person Doug T.    schedule 22.04.2011
comment
У меня тоже 0xA. Почему так чертовски сложно заставить iostream форматировать вещи так, как вы хотите ?? - person Emile Cormier; 23.04.2011
comment
У меня это сработало: cout << "0x" << setfill('0') << setw(2) << hex << 10 << endl - person Emile Cormier; 23.04.2011
comment
@Doug T .: Я взял на себя смелость отредактировать ваш ответ, чтобы OP мог принять его как ответ, который сработал. - person Emile Cormier; 23.04.2011
comment
@Potatoswatter: setw(2), похоже, не очень хорошо работает с showbase, по крайней мере, в gcc 4.4.3. Может это ошибка в GCC? - person Emile Cormier; 23.04.2011
comment
Когда я использую cout << showbase << setfill('0') << setw(2) << hex << 10 << endl;, я все равно получаю 0xa в GCC. - person Emile Cormier; 23.04.2011
comment
@EmileCormier: 0xa уже превышает 2 символа, поэтому setw(2) ничего не сделает. @Potatoswatter: В этом случае я считаю разумным явное 0x. setw(4) << hex << setfill('0') << showbase << 10 не даст желаемого эффекта (00xa!). - person CB Bailey; 23.04.2011
comment
@ Чарльз: Извини, я забыл setiosflags(ios::internal). Это работает: cout << showbase << setiosflags(ios::internal) << setfill('0') << setw(4) << hex << 10 << endl; Демо: ideone.com/WlusB - person Potatoswatter; 23.04.2011
comment
@Potatoswatter: Хорошо, я не знал, что это сработает! internal: добавляет символы заполнения в обозначенную внутреннюю точку в определенном сгенерированном выводе или идентично right, если такая точка не обозначена. Это либо недооценено, либо указано очень загадочно. - person CB Bailey; 23.04.2011
comment
@Charles @Emile, спасибо за помощь, у меня не было времени проверить свой ответ. Я думаю, мы показали, что iostreams может быть неприятно проверять, что они работают, просто взглянув. - person Doug T.; 23.04.2011
comment
@Charles: См. Таблицу 61, §22.2.2.2.2 / 19 (разве не цитируется iostreams fun? Действительно существует §22.2.2.2.2 / 22). @Doug: Без сомнения, iostreams - один из худших интерфейсов, который может стать достаточно портативным, чтобы кто-нибудь захотел его изучить. - person Potatoswatter; 23.04.2011
comment
я предпочитаю это, а не ускорение, вам просто нужно не забыть сбросить иоманипуляторы - person 463035818_is_not_a_number; 26.03.2019
comment
обратите внимание, что вам может потребоваться вызывать setw перед каждым << n, по крайней мере, так было для меня - person kraxor; 22.01.2021

Если вы хотите упростить вывод шестнадцатеричного числа, вы можете написать такую ​​функцию:

Обновленная версия представлена ​​ниже; Есть два способа вставить базовый индикатор 0x, с подробным описанием различий между ними в сносках. Исходная версия сохраняется внизу ответа, чтобы не доставить неудобств никому, кто ее использовал.

Обратите внимание, что как обновленная, так и исходная версии могут нуждаться в некоторой адаптации для систем, в которых размер байта кратен 9 битам.

#include <type_traits> // For integral_constant, is_same.
#include <string>      // For string.
#include <sstream>     // For stringstream.
#include <ios>         // For hex, internal, [optional] showbase.
                       // Note: <ios> is unnecessary if <iostream> is also included.
#include <iomanip>     // For setfill, setw.
#include <climits>     // For CHAR_BIT.

namespace detail {
    constexpr int HEX_DIGIT_BITS = 4;
    //constexpr int HEX_BASE_CHARS = 2; // Optional.  See footnote #2.

    // Replaced CharCheck with a much simpler trait.
    template<typename T> struct is_char
      : std::integral_constant<bool,
                               std::is_same<T, char>::value ||
                               std::is_same<T, signed char>::value ||
                               std::is_same<T, unsigned char>::value> {};
}

template<typename T>
std::string hex_out_s(T val) {
    using namespace detail;

    std::stringstream sformatter;
    sformatter << std::hex
               << std::internal
               << "0x"                                             // See footnote #1.
               << std::setfill('0')
               << std::setw(sizeof(T) * CHAR_BIT / HEX_DIGIT_BITS) // See footnote #2.
               << (is_char<T>::value ? static_cast<int>(val) : val);

    return sformatter.str();
}

Его можно использовать следующим образом:

uint32_t       hexU32 = 0x0f;
int            hexI   = 0x3c;
unsigned short hexUS  = 0x12;

std::cout << "uint32_t:       " << hex_out_s(hexU32) << '\n'
          << "int:            " << hex_out_s(hexI)   << '\n'
          << "unsigned short: " << hex_out_s(hexUS)  << std::endl;

См. Оба варианта (как описано в сносках ниже) в реальном времени: здесь.

Сноски:

  1. Эта строка отвечает за отображение базы и может быть одной из следующих:

    << "0x"
    << std::showbase
    
    • Первый вариант будет отображаться неправильно для пользовательских типов, которые пытаются выводить отрицательные шестнадцатеричные числа как -0x##, а не как <complement of 0x##>, со знаком, отображаемым после основания (как 0x-##), а не перед ним. Это очень редко проблема, поэтому я лично предпочитаю этот вариант.

      Если это проблема, то при использовании этих типов вы можете проверить наличие отрицательности перед выводом базы, а затем использовать abs() (или настраиваемый abs(), который возвращает беззнаковое значение, если вам нужно иметь возможность обрабатывать самые отрицательные значения в системе с дополнением до 2) на val.

    • Второй вариант будет опускать базу, когда val == 0, отображая (например, для int, где int - 32 бита) 0000000000 вместо ожидаемого 0x00000000. Это связано с тем, что флаг showbase внутренне обрабатывается как модификатор printf() #.

      Если это проблема, вы можете проверить val == 0, и применить специальные меры, когда это произойдет.

  2. В зависимости от того, какой вариант был выбран для отображения базы, нужно будет изменить две линии.

    • If using << "0x", then HEX_BASE_CHARS is unnecessary, and can be omitted.
    • При использовании << std::showbase значение, передаваемое в setw(), должно учитывать это:

      << std::setw((sizeof(T) * CHAR_BIT / HEX_DIGIT_BITS) + HEX_BASE_CHARS)
      

Исходная версия выглядит следующим образом:

// Helper structs and constants for hex_out_s().
namespace hex_out_helper {
    constexpr int HEX_DIGIT_BITS = 4; // One hex digit = 4 bits.
    constexpr int HEX_BASE_CHARS = 2; // For the "0x".

    template<typename T> struct CharCheck {
        using type = T;
    };

    template<> struct CharCheck<signed char> {
        using type = char;
    };

    template<> struct CharCheck<unsigned char> {
        using type = char;
    };

    template<typename T> using CharChecker = typename CharCheck<T>::type;
} // namespace hex_out_helper


template<typename T> std::string hex_out_s(T val) {
    using namespace hex_out_helper;

    std::stringstream sformatter;
    sformatter << std::hex
               << std::internal
               << std::showbase
               << std::setfill('0')
               << std::setw((sizeof(T) * CHAR_BIT / HEX_DIGIT_BITS) + HEX_BASE_CHARS)
               << (std::is_same<CharChecker<T>, char>{} ? static_cast<int>(val) : val);
    return sformatter.str();
}

Что затем можно использовать так:

uint32_t       hexU32 = 0x0f;
int            hexI   = 0x3c;
unsigned short hexUS  = 0x12;

std::cout << hex_out_s(hexU32) << std::endl;
std::cout << hex_out_s(hexI) << std::endl;
std::cout << "And let's not forget " << hex_out_s(hexUS) << std::endl;

Рабочий пример: здесь.

person Justin Time - Reinstate Monica    schedule 12.03.2016
comment
std::internal! Вы выиграли большой приз! Вот чего мне не хватало! Спасибо @Justin Time. - person j4x; 12.06.2017
comment
@fljx Пожалуйста. Я улучшил его с тех пор, как опубликовал этот ответ, поэтому я отредактирую ответ, чтобы отразить это. - person Justin Time - Reinstate Monica; 14.06.2017
comment
Необходимые включения должны быть где-то перечислены для этого, судя по тому, что я вижу: climits, iomanip, iostream, types, string, stringstream с настройками для CHAR_BIT, который заставил меня написать этот комментарий. - person mxmlnkn; 06.02.2018
comment
Хорошая идея, @mxmlnkn. Обновлено. (Кроме того, технически требуется ios вместо iostream, но это спорно, потому что iostream в любом случае требуется для включения ios. Это также отмечено в ответе.) - person Justin Time - Reinstate Monica; 08.07.2019
comment
Обратите внимание, что это может потребоваться изменить для поддержки C ++ 20 char8_t, и что также может быть полезно, чтобы он обрабатывал все типы символов ([[un]signed] char, charN_t, wchar_t) одинаково для удобства. В этом случае, вероятно, будет лучше привести к char_traits<T>::int_type, когда is_char<T> истинно, поскольку мы уже используем <string>. [В настоящее время я жду, чтобы увидеть, как все будет развиваться, прежде чем это сделать.] - person Justin Time - Reinstate Monica; 30.09.2019

Важная вещь, на которую отсутствует ответ, заключается в том, что вы должны использовать right со всеми вышеупомянутыми флагами:

cout<<"0x"<<hex<<setfill('0')<<setw(2)<<right<<10;
person lentz    schedule 16.10.2015
comment
Или, если вы используете std::showbase вместо прямого вывода 0x, вы используете std::internal вместо std::right. - person Justin Time - Reinstate Monica; 12.03.2016

В C ++ 20 вы сможете использовать для этого std::format :

std::cout << std::format("{:02x}\n", 10);  

Выход:

0a

А пока вы можете использовать библиотеку {fmt}, на основе std::format. {fmt} также предоставляет функцию print, которая делает это еще проще и эффективнее (godbolt):

fmt::print("{:02x}\n", 10); 

Заявление об ограничении ответственности: я являюсь автором {fmt} и C ++ 20 std::format.

person vitaut    schedule 03.03.2021

попробуйте это .. вы просто добавляете нули в зависимости от величины.

cout << hex << "0x" << ((c<16)?"0":"") << (static_cast<unsigned int>(c) & 0xFF) << "h" << endl;

Вы можете легко изменить это для работы с большими числами.

cout << hex << "0x";
cout << ((c<16)?"0":"") << ((c<256)?"0":"");
cout << (static_cast<unsigned int>(c) & 0xFFF) << "h" << endl;

Коэффициент равен 16 (для одной шестнадцатеричной цифры):
16, 256, 4096, 65536, 1048576, ..
соответственно
0x10, 0x100, 0x1000, 0x10000, 0x100000, ..

Поэтому вы также можете написать так ..

cout << hex << "0x" << ((c<0x10)?"0":"") << ((c<0x100)?"0":"") << ((c<0x1000)?"0":"") << (static_cast<unsigned int>(c) & 0xFFFF) << "h" << endl;

И так далее ..: P

person Michael Grieswald    schedule 19.08.2014

Чтобы сократить вывод в шестнадцатеричном формате, я сделал простой макрос

#define PADHEX(width, val) setfill('0') << setw(width) << std::hex << (unsigned)val

тогда

cout << "0x" << PADHEX(2, num) << endl;
person rwhenderson    schedule 24.02.2017
comment
Я улыбнулась. Написание C ++ иногда может быть настолько обременительным, что вам приходится прибегать к запретным областям, таким как макросы (он сказал, что макрос, он сказал, что макрос, убейте его, убейте его ... Жизнь Брайана, переосмысленная для C ++), чтобы сохранить его читабельным. - person 0xC0000022L; 14.07.2020

Выведите любое число в шестнадцатеричный формат с автоматическим заполнением «0» или установите. Шаблон допускает любой тип данных (например, uint8_t)

template<typename T, typename baseT=uint32_t> struct tohex_t {
    T num_;
    uint32_t width_;
    bool showbase_;

    tohex_t(T num, bool showbase = false, uint32_t width = 0) { num_ = num; showbase_ = showbase; width_ = width; }
    friend std::ostream& operator<< (std::ostream& stream, const tohex_t& num) {
        uint32_t w;
        baseT val;

        if (num.showbase_)
            stream << "0x";

        if (num.width_ == 0) {
            w = 0;
            val = static_cast<baseT>(num.num_);
            do { w += 2; val = val >> 8; } while (val > 0);
        }
        else {
            w = num.width_;
        }
        stream << std::hex << std::setfill('0') << std::setw(w) << static_cast<baseT>(num.num_);

        return stream;
    }
};
template<typename T> tohex_t<T> TO_HEX(T const &num, bool showbase = false, uint32_t width = 0) { return tohex_t<T>(num, showbase, width); }

Пример:

std::stringstream sstr;
uint8_t ch = 91;
sstr << TO_HEX(5) << ',' << TO_HEX(ch) << ',' << TO_HEX('0') << std::endl;
sstr << TO_HEX(1, true, 4) << ',' << TO_HEX(15) << ',' << TO_HEX(-1) << ',';
sstr << TO_HEX(513) << ',' << TO_HEX((1 << 16) + 3, true);
std::cout << sstr.str();

Выход:

05,5b,30
0x0001,0f,ffffffff,0201,0x010003
person Danilo Ramos    schedule 21.02.2018