:%s: :hello, world:
:%10s :hello, world:
:%.10s: :hello, wor:
:%-10s: :hello, world:
:%.15s: :hello, world:
:%-15s: :hello, world :
:%15.10s: : hello, wor:
:%-15.10s: :hello, wor :
Предостережение: функция printf использует свой первый аргумент, чтобы определить, сколько еще ожидается аргументов и какого они будут типа. Вы не получите правильного результата, если аргументов будет не хватать или они будут принадлежать не тому типу. Вы должны также понимать разницу в следующих двух обращениях:
printf(s); /* НЕВЕРНО, если в s есть % */
printf("%s", s); /* ВЕРНО всегда */
Функция sprintfвыполняет те же преобразования, что и printf , но вывод запоминает в строке
int sprintf(char *string, char *format, arg 1, arg 2,…)
Эта функция форматирует arg 1 , arg 2 и т. д. в соответствии с информацией, заданной аргументом format , как мы описывали ранее, но результат помещает не в стандартный вывод, а в string . Заметим, что строка string должна быть достаточно большой, чтобы в ней поместился результат.
Упражнение 7.2. Напишите программу, которая будет печатать разумным способом любой ввод. Как минимум она должна уметь печатать неграфические символы в восьмеричном или шестнадцатеричном виде (в форме, принятой на вашей машине), обрывая длинные текстовые строки.
7.3 Списки аргументов переменной длины
Этот параграф содержит реализацию минимальной версии printf . Приводится она для того, чтобы показать, как надо писать функции со списками аргументов переменной длины, причем такие, которые были бы переносимы. Поскольку нас главным образом интересует обработка аргументов, функцию minprintf напишем таким образом, что она в основном будет работать с задающей формат строкой и аргументами; что же касается форматных преобразований, то они будут осуществляться с помощью стандартного printf .
Объявление стандартной функции printf выглядит так:
int printf(char *fmt, …)
Многоточие в объявлении означает, что число и типы аргументов могут изменяться. Знак многоточие может стоять только в конце списка аргументов. Наша функция minprintf объявляется как
void minprintf(char *fmt, …)
поскольку она не будет выдавать число символов, как это делает printf .
Вся сложность в том, каким образом minprintf будет продвигаться вдоль списка аргументов, - ведь у этого списка нет даже имени. Стандартный заголовочный файл ‹stdarg.h›содержит набор макроопределений, которые устанавливают, как шагать по списку аргументов. Наполнение этого заголовочного файла может изменяться от машины к машине, но представленный им интерфейс везде одинаков.
Тип va_listслужит для описания переменной, которая будет по очереди указывать на каждый из аргументов; в minprintf эта переменная имеет имя ap (от " argument pointer " - указатель на аргумент). Макрос va_startинициализирует переменную ap ) чтобы она указывала на первый безымянный аргумент. К va_startнужно обратиться до первого использования ap . Среди аргументов по крайней мере один должен быть именованным: от последнего именованного аргумента этот макрос "отталкивается" при начальной установке.
Макрос va_argна каждом своем вызове выдает очередной аргумент, а ap передвигает на следующий: но имени типа он определяет тип возвращаемого значения и размер шага для выхода на следующий аргумент. Наконец, макрос va_endделает очистку всего, что необходимо. К va_endследует обратиться перед самым выходом из функции.
Перечисленные средства образуют основу нашей упрощенной версии prinf .
#include ‹stdarg.h›
/* minprintf: минимальный printf с переменным числом аргументов */
void minprintf(char *fmt, …)
{
va_list ap; /* указывает на очередной безымянный аргумент */
char *p, *sval;
int ival;
double dval;
va_start(ap, fmt); /* устанавливает ap на 1-й безымянный аргумент */
for (p=fmt; *p; p++) {
if (*p !='%') {
putchar(*p);
continue;
}
switch (*++p) {
case 'd':
ival = va_arg(ap, int);
printf ("%d", ival);
break;
case 'f':
dval = va_arg(ap, double);
printf("%f", dval);
break;
case 's':
for (sval = va_arg(ap, char *); *sval; sval++)
putchar(*sval);
break;
default:
putchar(*p);
break;
}
}
va_end(ap); /* очистка, когда все сделано */
}
Упражнение 7.3. Дополните minprintf другими возможностями printf .
Читать дальше