13.4  Форматированный вывод

Библиотека 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 и флаж­ки, определенные в этом классе, можно организовать форматированный ввод-вывод.