Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
c++book1.doc
Скачиваний:
0
Добавлен:
01.05.2025
Размер:
2 Мб
Скачать
☆

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

Пока << применялась только для неформатированного выво­да, и на самом деле в реальных программах она именно для это­го главным образом и применяется. Помимо этого существует также несколько форматирующих функций, создающих представле­ние своего параметра в виде строки, которая используется для вывода. Их второй (необязательный) параметр указывает, сколь­ко символьных позиций должно использоваться.

char* oct(long, int=0); // восьмеричное представление

char* dec(long, int=0); // десятичное представление

char* hex(long, int=0); // шестнадцатиричное представление

char* chr(int, int=0); // символ

char* str(char*, int=0); // строка

Если не задано поле нулевой длины, то будет производить­ся усечение или дополнение; иначе будет использоваться столь­ко символов (ровно), сколько нужно. Например:

cout << "dec(" << x

<< ") = oct(" << oct(x,6)

<< ") = hex(" << hex(x,4)

<< ")";

Если x==15, то в результате получится:

dec(15) = oct( 17) = hex( f);

Можно также использовать строку в общем формате:

char* form(char* format ...);

cout<<form() эквивалентно применению стандартной функции вывода языка C printf()*. form() возвращает строку, получае­мую в результате преобразования и форматирования ее парамет­ров, которые стоят после первого управляющего параметра - строки формата format. Строка формата состоит из объектов двух типов: обычных символов, которые просто копируются в по­ток вывода, и спецификаций преобразования, каждая из которых влечет преобразование и печать следующего из параметров. Каж­дая спецификация преобразования начинается с символа %. Нап­ример:

--------------------

* Объяснение того, как применяются строки формата, - это слегка отредактированный вариант спецификации printf(). (прим. автора)

cout<<form("there were %d members present",no_of_members);

Здесь %d указывает, что no_of_members должно рассматри­ваться как int и печататься в виде соответствующей последова­тельности десятичных цифр. Если no_of_members==127, вывод бу­дет такой:

there were 127 members present

Множество спецификаций преобразования довольно велико и обеспечивает высокую степень гибкости. После % может стоять:

- необязательный знак минус, который задает выравнивание преобразованного значения влево в указанном поле;

d необязательная строка цифр, задающая ширину поля. Если

преобразованное значение имеет меньше цифр, чем ширина

поля, оно будет дополняться пробелами слева (или справа,

если был задан индикатор выравнивания влево) до заполне­ния всей ширины поля; если ширина поля начинается с ну­ля, то вместо дополнения пробелами будет делаться допол­нение нулями;

. необязательная точка, для отделения ширины поля от следующей строки цифр;

d необязательная строка цифр, специфицирующая точность,

которая задает число цифр после десятичной точки для

преобразований e и f или печатаемых символов для строки;

* в ширине поля или точности вместо строки цифр может сто­ять *. В этом случае ширина поля и точность задается це­лым параметром;

h необязательный символ h; указывает на то, что идущие за

ним d, o, x или y соответствуют параметру короткое це­лое;

l необязательный символ h; указывает на то, что идущие за ним d, o, x или y соответствуют параметру длинное целое;

% указывает, что должен быть напечатан символ %, никакие

параметры при этом не затрагиваются;

c символ, указывающий, какой тип преобразования должен

применяться. Символы преобразования и их значения тако­вы:

d целый параметр преобразуется в десятичную запись;

o целый параметр преобразуется в восьмеричную запись;

x целый параметр преобразуется в шестнадцатиричную запись;

f параметр float или double преобразуется в десятичную запись вида [-]ddd.ddd, где число, задаваемое цифрами d после десятичной точки, эквивалентно спецификации точ­ности для параметра. Если точность опущена, дается шесть цифр; если точность явно задана как 0, то не печатается десятичная точка и не печатается ни одной цифры;

e параметр float или double преобразуется в десятичную запись вида [-]d.ddde+dd, где перед десятичной точкой стоит одна цифра, а число, задаваемое цифрами после де­сятичной точки, эквивалентно спецификации точности для параметра; когда точность опущена, выдается шесть цифр;

g параметр float или double печатается в том из видов d, f или e, который обеспечивает полную точность при мини­мальной затрате места;

c печатается символьный параметр, пустые символы игнори­руются;

s параметр воспринимается как строка (указатель на сим­вол), и печатаются символы из строки до пустого символа или до тех пор, пока не будет достигнуто число символов, указанное спецификацией точности; но если точность равна нулю, печатаются все символы до пустого;

u беззнаковый целый параметр преобразуется в десятичную запись.

Несуществующая или недостаточная ширина поля никогда не приводит к обрезанию поля; дополнение поля записи имеет место только в том случае, если указанная ширина поля превышает фактическую ширину.

Вот более сложный пример:

char* src_file_name;

int line;

char* line_format = "\n#line %d \"%s\"\n";

//...

cout << "int a;\n";

cout << form(line_format,line,src_file_name);

cout << "int b;\n";

который печатает

int a;

#line 13 "С++/main.c"

int b;

Применение form() небезопасно в смысле того, что не вы­полняется проверка типа. Вот, например, хорошо хорошо извест­ный способ получить непредсказуемый вывод и/или дамп (core dump):

char x;

// ...

cout<<form("bad input char: %s",x);

Правда, она дает большую гибкость в том виде, который хорошо знаком программистам на C. Потоковый вывод можно сме­шивать с выводом в стиле printf().

В настоящее время нет полностью удовлетворительных средств, обеспечивающих форматированный вывод типов, опреде­ляемых пользователем* В частности, вероятно нужно будет найти стандартный способ передавать функции вывода для определяемо­го пользователем типа информацию, которая позволит ей опреде­лить пространственные ограничения, вид заполнения, левое или правое выравнивание и т.п. такими, какими они определяются в ее вызове. Вполне осуществимый, но не идеальный подход состо­ит в том, чтобы снабжать определяемый пользователем тип функ­циями, которые порождают соответствующее строковое представ­ление объекта, для которого они вызываются, аналогично форматирующим функциям oct(), hex() и т.д. Например:

class complex (*

float re,im;

public:

// ...

char* string(char* format)

(* return form(format,re,im); *)

*);

// ...

cout << z.string("(%.3f,%.3f)");

Память для хранения строк, которые возвращают form(), hex() и т.п., берется из одного статически размещаемого цик­лического буфера, поэтому не имеет смысла сохранять указа­тель, возвращаемый любой из этих функций, для дальнейшего ис­пользования. Указываемые символы будут меняться.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]