Что делает 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.