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

#c #io #iostream #iomanip

#c #io #iostream #iomanip

Вопрос:

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

 #include  <iostream>

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

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

Комментарии:

1. Каковы именно ваши требования. В названии говорится 0x0a , в теле вашего вопроса говорится 0x0A . В любом случае явное std::cout << "0x0a" или std::cout << "0x0A" , по-видимому, соответствует вашим требованиям, но я предполагаю, что вы действительно хотите отформатировать число. Как вы хотите (например) 16, 255, 256, 65536, -1 что нужно отформатировать?

2. @Charles Вопрос был о том, как напечатать 0 после x и перед A, или a, если уж на то пошло. Как вы можете убедиться, первый ответ неверен, поскольку он по-прежнему выводит 0xa (0xA, если используется верхний регистр). Но в любом случае вопрос уже помечен как ответ.

3. Но зачем лишнее 0 ? Вы всегда хотите 0x0 или вам нужна минимальная длина строки?

4. Если шестнадцатеричное число равно 0xA, я хочу, чтобы оно было 0x0A. Если число равно 0x123, я хочу, чтобы оно было 0x0123, и так далее, то есть четное количество шестнадцатеричных цифр.

5. Я не думаю, что вы поняли, к чему я клоню. Вы точно указали, как вы хотите, чтобы отображалось 10, но как насчет 1-9 и 11-15? Как насчет 256? Вы хотите, 0x0a потому что вам нужна минимальная ширина или потому что вам всегда нужен начальный ноль? Если вы не соответствуете вашей спецификации, вы можете не получить ответы, которые вы хотите.

Ответ №1:

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

 #include  <iostream>
#include  <iomanip>

using namespace std;

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

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

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

int main()
{
    std::cout << boost::format("0xxn") % 10;
}
  

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

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

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

std::cout << format("{:#04x}n", 10);
  

Комментарии:

1. Этот ответ неверен. Если кто-то делал cout << left << whatever это раньше, вы получите неверный вывод из-за постоянного ввода-вывода влево / вправо. Это должно быть setfill('0') << setw(2) << right << hex , чтобы всегда гарантировать правильное выравнивание.

2. @fuujuhi неправильно ? Это довольно жестко. Я бы сказал, что это неполно. Тем не менее, спасибо за предложение.

3. @EmileCornier Извините, не хотел быть резким. Действительно, неполный, но, к сожалению, может привести к неприятным ошибкам. В последнее время в моем коде было две ошибки из-за постоянного iomanip (полное раскрытие: раньше я много кодировал на C , но не больше), и это заставило меня подумать, что C iostream ужасно неправильный. Для современного языка iostream превращает печать самых простых вещей в полный кошмар. Вы думаете, что печатаете целое число, но на самом деле вы печатаете его в шестнадцатеричном формате. Или вы получаете «0x90» на выходе, но на самом деле значение равно 0x09.

Ответ №2:

Используйте 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 с отслеживанием состояния. Я думаю, что формат boost — лучший вариант, поэтому я бы порекомендовал другой ответ.

Комментарии:

1. Я тоже получаю 0xA. Почему так чертовски СЛОЖНО заставить iostream форматировать вещи так, как вы хотите??

2. У меня это сработало: cout << "0x" << setfill('0') << setw(2) << hex << 10 << endl

3. @Doug T.: Я взял на себя смелость отредактировать ваш ответ, чтобы OP мог принять его как ответ, который сработал.

4. @Charles: Извините, я забыл setiosflags(ios::internal) . Это работает: cout << showbase << setiosflags(ios::internal) << setfill('0') << setw(4) << hex << 10 << endl; Демонстрация: ideone.com/WlusB

5. обратите внимание, что вам может потребоваться вызвать setw перед каждым << n , по крайней мере, для меня это было так

Ответ №3:

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

Ниже представлена обновленная версия; есть два способа вставить 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;
  

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

Footnotes:

  1. This line is responsible for showing the base, and can be either of the following:

     << "0x"
    << std::showbase
      
    • The first option will display improperly for custom types that try to output negative hex numbers as -0x## instead of as <complement of 0x##> , with the sign displaying after the base (as 0x-## ) instead of before it. This is very rarely an issue, so I personally prefer this option.

      If this is an issue, then when using these types, you can check for negativity before outputting the base, then using abs() (or a custom abs() that returns an unsigned value, if you need to be able to handle the most-negative values on a 2’s complement system) on val .

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

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

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

    • Если использование << "0x" , то HEX_BASE_CHARS не требуется и может быть опущено.
    • Если используется << 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;
  

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

Комментарии:

1. std::internal ! Вы выиграли большой приз! Это то, чего мне не хватало! Спасибо @Justin Time.

2. @fljx Всегда пожалуйста. Я улучшил его с тех пор, как опубликовал этот ответ, поэтому я отредактирую ответ, чтобы отразить это.

3. Для этого где-то должны быть указаны требуемые включения, на мой взгляд: climits , iomanip , iostream , types string , stringstream CHAR_BIT с ограничениями за то, что именно они заставили меня написать этот комментарий.

4. Хорошая идея, @mxmlnkn. Обновлено. (Кроме того, технически требуется ios вместо iostream , но это спорно, потому что iostream требуется включить ios в любом случае. Также отметил это в ответе.)

5. Обратите внимание, что это, возможно, потребуется изменить для поддержки C 20 char8_t , и что также может быть полезно, чтобы он обрабатывал все типы символов ( [[un]signed] char , charN_t , wchar_t ) одинаково для удобства. В этом случае, вероятно, будет лучше привести к char_traits<T>::int_type когда is_char<T> значение true, поскольку мы уже используем <string> . [Однако в настоящее время я жду, чтобы посмотреть, как все закончится, прежде чем делать это.]

Ответ №4:

В 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 .

Ответ №5:

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

 cout<<"0x"<<hex<<setfill('0')<<setw(2)<<right<<10;
  

Комментарии:

1. Или, если вы используете std::showbase вместо того, чтобы просто выводить 0x напрямую, вы используете std::internal вместо std::right .

Ответ №6:

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

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

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

 cout << hex << "0x";
cout << ((c<16)?"0":"") << ((c<256)?"0":"");
cout << (static_cast<unsigned int>(c) amp; 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) amp; 0xFFFF) << "h" << endl;
  

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

Ответ №7:

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

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

затем

 cout << "0x" << PADHEX(2, num) << endl;
  

Комментарии:

1. Я улыбнулся. Написание C иногда может быть настолько громоздким, что приходится прибегать к запретным областям, таким как макросы («он сказал макрос, он сказал макрос», «убей его, убей его» … Life of Brian переосмыслен для C ), чтобы сохранить его читаемым.

Ответ №8:

Выведите любое число в шестнадцатеричном формате с автоматическим заполнением ‘0’ или set. Шаблон допускает любой тип данных (например, 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::ostreamamp; operator<< (std::ostreamamp; stream, const tohex_tamp; 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 amp;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
  

Ответ №9:

 #include <iostream>
#include <iomanip>
using namespace std;
int main()
{
    /*This should print out 0x0a. The internal adjustment pads the width with the fill character*/
    cout << hex << showbase << internal << setfill('0') << setw(4) << 10 << endl;
}