Бьерн Страуструп - Язык программирования С++. Главы 9-10
Страница 43. Ввод-вывод в С



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

Поскольку текст программ на С и на С++ часто путают, то путают иногда
и потоковый ввод-вывод С++ и функции ввода-вывода семейства  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.
    За подробностями о вводе-выводе на С отсылаем к вашему руководству
по С или книге Кернигана и Ритчи "Язык программирования С".

 
« Предыдущая статья   Следующая статья »