#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/WlusB5. обратите внимание, что вам может потребоваться вызвать 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:
-
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 (as0x-##
) 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 customabs()
that returns an unsigned value, if you need to be able to handle the most-negative values on a 2’s complement system) onval
. -
Второй вариант будет опускать базовое значение при
val == 0
отображении (например, дляint
, гдеint
это 32 бита)0000000000
вместо ожидаемого0x00000000
. Это связано с тем, чтоshowbase
флаг обрабатывается какprintf()
модификатор#
внутри.Если это проблема, вы можете проверить, есть ли
val == 0
и применить специальную обработку, когда это произойдет.
-
-
В зависимости от того, какой вариант был выбран для отображения базы, необходимо будет изменить две строки.
- Если использование
<< "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;
}