Библиотека iostream содержит средства, позволяющие выдать данные в той или иной системе счисления с различной точностью, прижатыми к левому или правому концу поля. Средства форматированного вывода позволяют управлять и другими деталями формата выдачи. Все эти нюансы определяются несколькими функциями и флажками, заданными в классе ios битами переменной состояния форматизации следующим образом:
class ios
{
public:
enum
{
skipws = 0x0001, // Пропускать пробелы при вводе
left = 0x0002, // Прижать к левому концу поля
right = 0x0004, // Прижать к правому концу поля
internal = 0x0008, // Расположить по центру поля
dec = 0x0010, // Десятичная система счисления
oct = 0x0020, // Восьмеричная система счисления
hex = 0x0040, // Шестнадцатеричная система счисления
showbase = 0x0080, // Показать базу счисления
showpoint = 0x0100, // Отобразить десятичную точку
uppercase = 0x0200, // Печатать шестнадцатеричными буквами
showpos = 0x0400, // Печатать "+" перед положительными числами
scientific = 0x0800, // Для плавающих чисел использовать букву Е;
fixed = 0x1000, // Для плавающих чисел использовать точку 123.45
unitbuf = 0x2000, // Выгрузить все потоки после ввода
stdio = 0x4000 // Выгрузить потоки после вывода
};
inline long setf(long _f,long _m);
inline long setf(long _l);
inline long unsetf(long _l);
};
Любой флажок можно установить или сбросить с помощью перегружаемых функций setf() и unsetf(). Например, по умолчанию действует десятичная система счисления. Программист может изменить базу системы счисления на восьмеричную или шестнадцатеричную с помощью функции setf(). Эта функция перегружаемая с одним и двумя аргументами.
Первый аргумент задает конкретный бит, который нужно установить. Он может быть одним из флажков, заданных в перечислении. Чтобы включить сразу несколько флажков, их нужно связать побитовой операцией «или» (|).
Некоторые флажки не могут быть заданы одновременно. Например, нельзя одновременно использовать и восьмеричную, и шестнадцатеричную системы счисления. Если просто задать
setf(oct);
setf(hex);
то окажутся включенными оба флажка.
То же самое относится к форме выдачи плавающих чисел. Нельзя одновременно использовать и обыкновенную, и научную нотацию. Для таких случаев используется перегружаемая функция setf() с двумя аргументами. Здесь вторым аргументом задается группа флажков, которые необходимо сбросить перед тем, как выполнить установку битов, заданных первым аргументом (табл. 13.1). На месте второго аргумента может появляться одно из двух значений, которые тоже определены в классе ios.
Таблица 13.1 Аргументы функции setf()
Имя второго аргумента |
Имя первого аргумента |
Действие флажков |
ios::basefield |
ios::hex ios::oct ios::dec |
Целые |
ios::floatfield |
ios::fixed ios::scientific |
Плавающие |
ios::adjustfield |
ios::left ios::right ios:: internal |
Формы выдачи |
Такие формы установки (табл. 13.1) гарантируют, что не окажутся одновременно установленными два флажка. Например, чтобы установить шестнадцатеричную систему счисления, нужно написать:
cout.setf(ios::hex, ios::basefield);
Эта функция вначале сбросит в нуль все биты, относящиеся к системе счисления, а затем установит нужный бит.
Точно так же после вызова функции setf():
cout.setf(ios::scientific, ios::floatfield);
числа с плавающей точкой будут печататься в научной нотации. По умолчанию любое значение печатается прижатым к правому концу поля. После установки флажка left значение будет печататься прижатым к левому концу поля. Это можно сделать следующим образом:
cout.setf(ios::left, ios:;adjustfield);
Остальные флажки можно установить функцией setf(), имеющей один аргумент. Функция setf() возвращает предыдущее состояние флажков форматизации в виде числа long. Если это состояние сохранить, то затем его легко можно восстановить. Например:
long old_stform = setf(ios::left, ios::adjustfield;
…
setf(old_stform, ios::adjustfleld);
По умолчанию выдается столько символов, сколько необходимо для правильного представления значения, т.е. число не будет дополняться слева или справа пробелами. Поэтому устанавливать флажок левого или правого конца поля при не установленной ширине поля выдачи не имеет смысла, так как ширина поля соответствует числу символов в числе, и значение одновременно прижато и к левому, и к правому концу. Но программист может сам задать ширину выводимого поля с помощью член-функции width(). Функция width () перегружаемая и имеет два прототипа:
int ios::width(int w);
int ios::width();
Первый экземпляр устанавливает ширину печатного поля в переменной w и возвращает предыдущую ширину. Заметим, что если задать в функции width() недостаточное количество позиций, то никакого усечения происходить не будет, а будут печататься все цифры числа. Если ширина поля выдачи задана больше, чем необходимо для числа, то значение слева будет дополнено пробелами. Если при этом включен флажок левого конца поля, то число будет дополняться пробелами справа. Например:
int count1 = 89786, count2 = 7834;
int old_wd = cout.width(l0);
cout << count1 << count2 << "n";
cout.width(old_wd);
cout << count1 << count2 << "n";
cout << count1;
cout << count2 << "n";
В результате получим:
89786 7834
897867834
В этой программе мы установили ширину поля 10 позиций, сохранив состояние по умолчанию в переменной old_wd. Оператор выдачи cout << напечатает значения переменных прижатыми к правому концу поля и дополнит слева до 10 позиций пробелами. После этого функция width() восстановит состояние по умолчанию, используя для этой цели переменную old_wd, в которой сохранено состояние форматизации по умолчанию.
По умолчанию ширина поля вывода – нуль, а это значит, что будут печататься только значащие цифры и никакого дополнения пробелами ни слева, ни справа не будет. Поэтому значения двух переменных напечатаются слитно, функция width() имеет еще один прототип, который не получает аргументов. Такая функция ничего не изменяет, а просто возвращает текущее значение ширины поля выдачи.
Установленная ширина поля будет сбрасываться в нуль после выполнения любой операции вывода, как, например:
int а, b;
cout.width(7);
cout << а << b << "n";
В подобном примере установленная в 7 ширина поля будет действительна только в момент выдачи переменной а. Переменные "b" и "n" будут использовать для выдачи ширину поля по умолчанию.
Как упоминалось ранее, если программист установил с помощью функции width() ширину поля выдачи, превышающую необходимый минимум, то значение будет дополняться слева или справа пробелами. Пробел является символом-заполнителем по умолчанию. Но с помощью член-функции fill() программист может изменить символ-заполнитель. Например:
int L = 7834;
cout.fill(‘#’);
cout.width(8);
cout << L; // Будет напечатано ####7834
Если использовать флажок left, то вывод будет другим:
int L = 7834;
cout.fill(‘#’);
cout.width(8);
cout.setf(ios::left, ios::adjustfield);
cout << L; // Будет напечатано 7834####
При работе с числами с плавающей точкой программист тоже имеет возможность выбора вида выводимого числа. С помощью флажков ios::fixed и ios::scientific можно выбрать нотацию плавающего числа – обыкновенную или научную:
cout.setf(ios::fixed, ios::floatfield);
Выводимое число с плавающей точкой будет печататься в обыкновенной нотации. Кроме этого, программисту предоставлена возможность регулировать точность выводимого числа, т.е. задавать количество цифр после точки. Для этого можно использовать член-функцию precision().
Функция precision(), как и предыдущие функции, перегружаемая и имеет два прототипа:
int precision(int);
int precision();
Первый формат используется, чтобы установить количество печатаемых знаков после десятичной точки. Эта функция возвращает точность, которая использовалась до переустановки. Второй формат функции precision () не изменяет точность, а просто возвращает текущее количество знаков, печатаемых после точки.
По умолчанию печатается шесть значащих цифр после точки. Завершающие нули после десятичной точки усекаются, даже если они заданы явно. Например:
cout << 55.7700 << "n";
Будет выдано
55.77
Если после десятичной точки стоят только нули, то усекаются и нули, и десятичная точка. Например:
cout << 77.00 << "n";
Будет выдано
77
Если необходимо напечатать все завершающие нули после десятичной точки, необходимо установить флажок ios::showpoint. Например:
cout.setf(ios::showpoint);
cout << 77.0000 << "n";
Теперь будет выдано
77.000000
По умолчанию после десятичной точки выдаётся шесть цифр.
Изменим количество выводимых цифр после десятичной точки:
cout.setf(ios::showpoint);
cout.precision(12);
cout << 77.00 << "n";
cout << "Сейчас после точки печатается " << cout.precision() << "цифр n";
Этот фрагмент выведет на экран
77.000000000000
Сейчас после точки печатается 12 цифр
Вызов cout.precision (12) определил, что после точки нужно печатать 12 знаков. Установка флажка showpoint обеспечила печать двенадцати знаков после точки, даже если это завершающие нули.
Вызов функции precision () без аргументов определил, какова точность в настоящий момент.
Таким образом, комбинируя функции-члены класса ios и флажки, определенные в этом классе, можно организовать форматированный ввод-вывод.