Язык программирования C++ для профессионалов

       

Ввод-вывод в С


Поскольку текст программ на С и на С++ часто путают, то путают иногда и потоковый ввод-вывод С++ и функции ввода-вывода семейства printf для языка С. Далее, т.к. С-функции можно вызывать из программы на С++, то многие предпочитают использовать более знакомые функции ввода-вывода С.

По этой причине здесь будет дана основа функций ввода-вывода С. Обычно операции ввода-вывода на С и на С++ могут идти по очереди на уровне строк. Перемешивание их на уровне посимвольного ввода-вывода возможно для некоторых реализаций, но такая программа может быть непереносимой. Некоторые реализации потоковой библиотеки С++ при допущении ввода-вывода на С требуют вызова статической функции-члена ios::sync_with_stdio().

В общем, потоковые функции вывода имеют перед стандартной функцией С printf() то преимущество, что потоковые функции обладают определенной типовой надежностью и единообразно определяют вывод объектов предопределенного и пользовательского типов.

Основная функция вывода С есть

int printf(const char* format, ...)

и она выводит произвольную последовательность параметров в формате, задаваемом строкой форматирования format. Строка форматирования состоит из объектов двух типов: простые символы, которые просто копируются в выходной поток, и спецификации преобразований, каждая из которых преобразует и печатает очередной параметр. Каждая спецификация преобразования начинается с символа %, например

printf("there were %d members present.",no_of_members);

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

there were 127 members present.

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

  • - необязательный знак минус, задающий выравнивание влево в указанном поле для преобразованного значения;
  • d необязательная строка цифр, задающая ширину поля; если в преобразованном значении меньше символов, чем ширина строки, то оно дополнится до ширины поля пробелами слева (или справа, если дана спецификация выравнивания влево); если строка ширины поля начинается с нуля, то дополнение будет проводится нулями, а не пробелами;
  • . необязательный символ точка служит для отделения ширины поля от последующей строки цифр;
  • d необязательная строка цифр, задающая точность, которая определяет число цифр после десятичной точки для значений в спецификациях e или f, или же задает максимальное число печатаемых символов строки;
  • * для задания ширины поля или точности может использоваться * вместо строки цифр. В этом случае должен быть параметр целого типа, который содержит значение ширины поля или точности;
  • h необязательный символ h указывает, что последующая спецификация d, o, x или u относится к параметру типа короткое целое;
  • l необязательный символ l указывает, что последующая спецификация d, o, x или u относится к параметру типа длинное целое;
  • % обозначает, что нужно напечатать сам символ %; параметр не нужен;
  • c символ, указывающий тип требуемого преобразования.Символы преобразования и их смысл следующие:
  • d Целый параметр выдается в десятичной записи;
  • o Целый параметр выдается в восьмеричной записи;
  • x Целый параметр выдается в шестнадцатеричной записи;
  • f Вещественный или с двойной точностью параметр выдается в десятичной записи вида [-]ddd.ddd, где число цифр после точки равно спецификации точности для параметра. Если точность не задана, печатается шесть цифр; если явно задана точность 0, точка и цифры после нее не печатаются;
  • e Вещественный или с двойной точностью параметр выдается в десятичной записи вида [-]d.ddde+dd; здесь одна цифра перед точкой, а число цифр после точки равно спецификации точности для параметра; если она не задана печатается шесть цифр;
  • g Вещественный или с двойной точностью параметр печатается по той спецификации d, f или e, которая дает большую точность при меньшей ширине поля;
  • c Символьный параметр печатается. Нулевые символы игнорируются;
  • s Параметр считается строкой (символьный указатель), и печатаются символы из строки до нулевого символа или до достижения числа символов, равного спецификации точности; но, если точность равна 0 или не указана, печатаются все символы до нулевого;
  • p Параметр считается указателем и его вид на печати зависит от реализации;
  • u Беззнаковый целый параметр печатается в десятичной записи. Несуществующее поле или поле с шириной, меньшей реальной, приведет к усечению поля. Дополнение пробелами происходит, если только спецификация ширины поля больше реальной ширины.


Ниже приведен более сложный пример:

char* src_file_name; int line; char* line_format = "\n#line %d \"%s\"\n"; main() { line = 13; src_file_name = "C++/main.c";

printf("int a;\n"); printf(line_format,line,src_file_name); printf("int b;\n"); }

в котором печатается

int a;

#line 13 "C++/main.c" int b;

Использование printf() ненадежно в том смысле, что нет никакого контроля типов. Так, ниже приведен известный способ получения неожиданного результата - печати мусорного значения или чего похуже:

char x; // ... printf("bad input char: %s",x);

Однако, эти функции обеспечивают большую гибкость и знакомы программирующим на С.

Как обычно, getchar() позволяет знакомым способом читать символы из входного потока:

int i;: while ((i=getchar())!=EOF) { // символьный ввод C // используем i }

Обратите внимание: чтобы было законным сравнение с величиной EOF типа int при проверке на конец файла, результат getchar() надо помещать в переменную типа int, а не char.

За подробностями о вводе-выводе на С отсылаем к вашему руководству по С или книге Кернигана и Ритчи "Язык программирования С".


Содержание раздела