Что делает cout << std:: ios:: hex do?
Этот вопрос исходит из ошибки, с которой я недавно столкнулся. Я пытался сохранить некоторые целочисленные значения для файла как hex. В качестве примера, это то, что я должен сделать:
cout << std::hex << value << endl; // (1)
Но по ошибке я использую его как следующее:
cout << std::ios::hex << value << endl; // (2)
Компилятор не жалуется, но, очевидно, результат неверен. Я несколько раз пытался оценить несколько значений, и кажется, что (2) фактически дает частично правильный результат, за исключением того, что он добавляет 800 в качестве префикса. Я не понимаю, откуда приходит 800, и я не вижу хорошей ссылки нигде. Может ли кто-нибудь объяснить, что происходит под капотом?
cout << std::hex << 255 << endl; // output: FF
cout << std::ios::hex << 255 << endl; // output: 800ff
cout << std::hex << 135 << endl; // output: 87
cout << std::ios::hex << 135 << endl; // output: 80087
cout << std::hex << 11 << endl; // output: b
cout << std::ios::hex << 11 << endl; // output: 800b
Ответы
Ответ 1
Это фактически std::ios_base::hex
. Это определенная реализацией битовая маска. Внутренне поток имеет целое число fmtflags
, где хранится текущее состояние форматирования.
В вашей реализации hex
есть флаг 0x800
. Другие флаги будут указывать, включен ли он в режиме научной нотации, включен ли boolalpha
и т.д. И т.д.
Функция std::hex
устанавливает флаг std::ios_base::hex
в fmtflags
.
Таким образом, ваш вывод представляет собой целочисленное значение этого флага (в шестнадцатеричном виде с тех пор, как вы отправили std::hex
ранее).
Ответ 2
std::hex
является манипулятором, т.е. является функцией со специальной сигнатурой:
std::ios_base& hex(std::ios_base& stream) {
stream.setf(std::ios_base::hex, std::ios_base::basefield);
return stream;
}
Для потока обрабатываются манипуляторы. Для версии, использующей ссылки на std::ios_base
, существует (игнорирование того, что оператор фактически является шаблоном функции):
std::ostream& operator<< (std::ostream& out, std::ios_base&(*manip)(std::ios_base&));
При использовании с потоком функция манипулятора вызывается и устанавливает флаг определенного формата, в данном случае std::ios_base::hex
(как это определено std::ios::hex
). Так как std::ios_base::hex
является членом группы флагов (остальные - std::ios_base::dec
и std::ios_base::oct
), то также необходимо очистить любой потенциальный другой флаг в группе. Таким образом, setf()
вызывается с помощью маски (std::ios_base::basefield
), чтобы очистить любой из возможных потенциально установленных флагов.
Флаги формата std::ios_base::fmtflags
- это битовая маска. Значение std::ios_base::hex
является одним из значений. При форматировании вы получите некоторое количество, скорее всего, мощность 2 (однако, она не должна быть 2). Значение, которое вы видите, просто 0x800
(т.е. 2048), напечатанное с использованием шестнадцатеричной нотации: установка любого из флагов форматирования (кроме width()
) является липкой, т.е. Они остаются до тех пор, пока флаг не будет удален. Если вы хотите увидеть значение 2048 (для реализации, которую вы используете), вы должны использовать
std::cout << std::dec << std::ios_base::hex << "\n"; // 2048
std::cout << std::hex << std::ios_base::hex << "\n"; // 800
std::cout << std::showbase << std::ios_base::hex << "\n"; // 0x800
Последняя строка устанавливает флаг showbase
, который указывает базу целочисленного значения с префиксом:
- no prefix = > decimal
- ведущий
0x
= > шестнадцатеричный
- ведущий
0
(но не x
) = > восьмеричный
Ответ 3
std::hex
- это специальный объект, который при применении к потоку с использованием operator<<
,
устанавливает базовое поле потока str
в hex, как если бы он вызывал str.setf(std::ios_base::hex, std::ios_base::base field)
std::ios::hex
(aka std::ios_base::hex
) - это фактическое значение битмаски, которое передается методу setf
. Его значение определяется реализацией, и в вашем случае это выглядит как 0x800
.