Предопределенные объекты и потоки
В стандартной библиотеке ввода/вывода стандартного Си (заголовочный файл библиотеки - <stdio.h>) имеются внешние переменные-указатели на дескрипторы файлов - стандартных устройств ввода-вывода.
extern FILE *stdin, *stdout, *stderr, *stdaux, *stdprn; ^ ^ ^ ^ ^стандартный ввод • | | | |стандартный вывод •------• | | |регистрация ошибок •--------------• | |дополнительное устройство •----------------• |устройство печати •---------------------------------•Эти файлы открываются библиотекой автоматически перед выполнением функции main и по умолчанию назначаются на терминал (stdin - клавиатура, stdout, stderr - экран), последовательный порт (stdaux) и принтер (stdprn), stdin и stdout могут быть переназначены в командой строке запуска программы на любые другие файлы:
>test.exe <a.dat >c:\xxx\b.dat ^ ^ | • файл замещения stdout • файл замещения stdinВ Си++ существуют классы потоков ввода-вывода, которые являются объектно-ориентированным эквивалентом (iostream.h) стандартной библиотеки ввода-вывода (stdio.h):
ios | базовый потоковый класс; |
streambuf | буферизация потоков; |
istream | потоки ввода; |
ostream | потоки вывода; |
iostream | двунаправленные потоки; |
iostream_withassign | поток с переопределенной операцией присваивания; |
istrstream | строковые потоки ввода; |
ostrstream | строковые потоки вывода; |
strstream | двунаправленные строковые потоки; |
ifstream | файловые потоки ввода; |
ofstream | файловые потоки вывода; |
fstream | двунаправленные файловые потоки. |
Стандартные потоки (istream,ostream,iostream) служат для работы с терминалом. Строковые потоки (istrstream, ostrstream, strstream) служат для ввода-вывода из строковых буферов, размещенных в памяти. Файловые потоки (ifstream, ofstream, fstream) служат для работы с файлами.
Следующие объекты-потоки заранее определены и открыты в программе перед вызовом функции main:
extern istream cin; // Стандартный поток ввода с клавиатурыextern ostream cout;// Стандартный поток вывода на экранextern ostream cerr;// Стандартный поток вывода сообщений об ошибках (экран)extern ostream clog;// Стандартный буферизованный поток вывода сообщений об ошибках (экран).Операции помещения и извлечения
Для начала рассмотрим пример:
#include <iostream.h>main(){ cout << "Hello, world\n";}Строка #include <iostream.h> сообщает компилятору, чтобы он включил стандартные возможности потока ввода и вывода, находящиеся в файле iostream.h. Без этих описаний выражение cout << "Hello, world\n" не имело бы смысла. Операция << ("поместить в") пишет свой первый аргумент во второй (в данном случае, строку "Hello, world\n" в стандартный поток вывода cout). Программирующим на C << известно как операция сдвига влево для целых. Такое использование << не утеряно, просто в дальнейшем << было определено для случая, когда его левый операнд является потоком вывода.
Ввод производится с помощью операции >> ("извлечь из") над стандартным потоком ввода cin. Описания cin и >>, конечно же, находятся в <iostream.h>. Операцию вывода << можно применять к ее собственному результату, так что несколько команд вывода можно записать одним оператором:
cout << inch << " in = " << inch*2.54 << "cm\n";Операция вывода используется, чтобы избежать той многословности, которую дало бы использование функции вывода. Но почему <<? Возможности изобрести новый лексический символ нет. Операция присваивания была кандидатом одновременно и на ввод, и на вывод, но оказывается, большинство людей предпочитают, чтобы операция ввода отличалась от операции вывода. Кроме того, = не в ту сторону связывается (ассоциируется), то есть cout=a=b означает cout=(a=b).
Делались попытки использовать операции "<" и ">", но значения "меньше" и "больше" настолько прочно вросли в сознание людей, что новые операции ввода/вывода во всех реальных случаях оказались нечитаемыми. Помимо этого, "<" находится на большинстве клавиатур как раз на ",", и у людей получаются операторы вроде такого:
cout< x, y, z;
Для таких операторов непросто выдавать хорошие сообщения об ошибках.
Операции << и >> к такого рода проблемам не приводят, они асимметричны в том смысле, что их можно проассоциировать с "в" и "из", а приоритет << достаточно низок, чтобы можно было не использовать скобки для арифметических выражений в роли операндов. Например:
cout << "a*b+c=" << a*b+c << "\n";Естественно, при написании выражений, которые содержат операции с более низкими приоритетами, скобки использовать надо. Например:
cout << "a^b|c=" << (a^b|c) << "\n";Операцию левого сдвига тоже можно применять в операторе вывода:
cout << "a<<b=" << (a<<b) << "\n";В С++ нет выражений с символьными значениями. Для печати символов предоставляются функции ostream::put(char) и chr(int). B частности, '\n' является целым (со значением 10, если используется набор символов ASCII), поэтому
cout << "x = " << x << '\n';напечатает число 10, а не ожидаемый символ новой строки. Эту и аналогичные проблемы можно сгладить, определив несколько макросов (в которых используются стандартные имена символов ASCII):
#define sp << " "#define ht << "\t"#define nl << "\n"Теперь предыдущий пример запишется в виде:
cout << "x = " << x nl;
Некоторые выражения кажутся трудно читаемыми из-за большого числа кавычек и того, что операция вывода внешне выглядит слишком непривычно.
cout << x << " " << y << " " << z << "\n";cout << "x = " << x << ", y = " << y << "\n";Здесь могут помочь приведенные выше макросы и несколько отступов:
cout << x sp << y sp << z nl;cout << "x = " << x << ", y = " << y nl;