Почему функции ввода не могут следовать за функциями вывода или наоборот в C? - PullRequest
0 голосов
/ 07 января 2019

В моем учебнике написано:

"Функция ввода не может следовать за функцией вывода без промежуточного вызова fflush, fseek, fsetpos или rewind и наоборот Первое ограничение на потоковый ввод-вывод можно обойти, приняв дисциплину очистки буфера перед каждой операцией ввода. Однако единственный способ обойти второе ограничение - открыть два потока в одном и том же дескрипторе открытого сокета, один для чтения и один для записи. "

Итак, мои вопросы:

  1. Почему функции ввода не могут следовать за функциями вывода или наоборот?
  2. Почему второе ограничение нельзя исправить, добавив операцию fflush?

1 Ответ

0 голосов
/ 07 января 2019

Стандарт C говорит что-то немного похожее, и ваша книга, по-видимому, перефразирует то, что говорит:

C11 .217.21.5.3 Функция fopen

¶7 Когда файл открывается в режиме обновления («+» в качестве второго или третьего символа в приведенном выше списке значений аргументов режима), ввод и вывод могут выполняться в связанном потоке. Однако за выводом не должен следовать непосредственно ввод без промежуточного вызова функции fflush или функции позиционирования файла (fseek, fsetpos или rewind), и за вводом не должен следовать непосредственно вывод без промежуточного вызова функции позиционирования файла, если только операция ввода не встречает конец файла. Открытие (или создание) текстового файла в режиме обновления может вместо этого открыть (или создать) двоичный поток в некоторых реализациях.

Правила позволяют библиотеке держать вещи под контролем. Может потребоваться очистить символы, выдвинутые обратно ungetc(), или организовать очистку вывода, чтобы ввод мог быть выполнен разумно, или что-то еще. Обратите внимание, что эти правила предназначены для файловых потоков (FILE *). Чаще всего, когда вы работаете с сокетами, вы используете файловые дескрипторы (int), а не файловые потоки, и эти правила просто неприменимы.

Обратите внимание, что fseek(fp, 0, SEEK_CUR) - это операция позиционирования, которая оставляет позицию ввода там, где она находится (поиск нулевых байтов от текущего смещения), за исключением, возможно, потери символов, отталкиваемой назад ungetc().

Использование fflush() - сложный способ выполнения операций по сравнению с использованием fseek().

При использовании сокетов один дескриптор файла используется как для чтения, так и для записи удаленной стороне. Но поскольку функции файлового дескриптора не имеют буферизации, нет никакой путаницы в отношении того, что делать с данными, которые были прочитаны, но еще не использованы (что может легко случиться при чтении через стандартный поток ввода-вывода), и при этом не возникает путаницы что делать с данными, которые были записаны в буферы ввода / вывода, но еще не отправлены на удаленный компьютер. Кроме того, сокеты не являются поисковыми устройствами, в отличие от файлов на диске. Каналы, FIFO, терминалы и многие другие не дисковые, не ленточные устройства также не доступны. Это не освобождает вас от следования правилам, но обновляемые потоки обычно предназначены для таких устройств, как диски, на которых вы сможете прочитать то, что написали, что неверно для устройств без возможности поиска.

Итак, если вам действительно нужны файловые потоки для сокетного ввода-вывода, вы, вероятно, захотите использовать два отдельных потока, один исключительно для чтения и один исключительно для записи. В системе POSIX вы можете использовать dup() или dup2() для создания копии дескриптора файла сокета, а затем дважды использовать fdopen() для создания потоков чтения и записи.

...