Использование FILE * f = stdin; - PullRequest
0 голосов
/ 15 апреля 2020

Я хочу (ed) реализовать хвост POSIX на языке C. Если вход является файлом (имя файла получено из argv), тогда я использовал fseek, чтобы получить конец файла, поэтому реализация была как-то проста.

Но когда ввод - stdin, я не могу использовать fseek. Я как-то понял, что я могу сделать:

FILE *f = stdin;

Тогда я могу использовать stdin в качестве файла и fseek, все работает как задумано (с небольшой работой: D).

Мой вопрос только, это нормально? Я имею в виду (для меня) довольно необычно использовать stdin таким образом. Не будет ли здесь «безопасности» или других ошибок? Я много тестировал свой хвост, и, похоже, он хорошо работает даже в крайних случаях.

1 Ответ

2 голосов
/ 15 апреля 2020

Это действительно странная вещь, потому что это не помогает. Работает ли fseek или нет, не зависит от имени переменной, используемой в качестве аргумента.

Может быть успешным, если дескриптор для простого файла.
Не может быть успешным, если хэндл не для простого файла.

Это верно для fseek(stdin, ...). (Код ниже.)

$ ./fseek_stdin <file
fghij

$ cat file | ./fseek_stdin
fseek: Illegal seek

Это верно для fseek(f, ...). (Код ниже.)

$ ./fseek_f <file
fghij

$ cat file | ./fseek_f
fseek: Illegal seek

Но при назначении stdin другой переменной также нет никакого вреда. Например, вы могли бы сделать

FILE *f;
if (...) {
   f = stdin;
} else {
   f = fopen(...);
}

Или вы могли бы сделать

void some_func(FILE *f) {
   ...
}

some_func(stdin);

Это оба совершенно законные присвоения stdin другой переменной.


Вот файлы, использованные в предыдущих тестах:

file:

abcdefghij

fseek_stdin.c:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
   if (fseek(stdin, 5, SEEK_CUR) < 0) {
      perror("fseek");
      return EXIT_FAILURE;
   }

   char *line = NULL;
   size_t n = 0;
   if (getline(&line, &n, stdin) < 0) {
      perror("getline");
      free(line);
      return EXIT_FAILURE;
   }

   printf("%s", line);
   free(line);
   return EXIT_SUCCESS;
}

fseek_f.c:

#include <stdio.h>
#include <stdlib.h>

int main(void) {
   FILE *f = stdin;

   if (fseek(f, 5, SEEK_CUR) < 0) {
      perror("fseek");
      return EXIT_FAILURE;
   }

   char *line = NULL;
   size_t n = 0;
   if (getline(&line, &n, f) < 0) {
      perror("getline");
      free(line);
      return EXIT_FAILURE;
   }

   printf("%s", line);
   free(line);
   return EXIT_SUCCESS;
}

Разница двух программ (слегка массируется для удобства чтения):

$ diff -y fseek_{stdin,f}.c
#include <stdio.h>                               #include <stdio.h>
#include <stdlib.h>                              #include <stdlib.h>

int main(void) {                                 int main(void) {
                                               >    FILE *f = stdin;
                                               >
   if (fseek(stdin, 5, SEEK_CUR) < 0) {        |    if (fseek(f, 5, SEEK_CUR) < 0) {
      perror("fseek");                                 perror("fseek");
      return EXIT_FAILURE;                             return EXIT_FAILURE;
   }                                                }

   char *line = NULL;                               char *line = NULL;
   size_t n = 0;                                    size_t n = 0;
   if (getline(&line, &n, stdin) < 0) {        |    if (getline(&line, &n, f) < 0) {
      perror("getline");                               perror("getline");
      free(line);                                      free(line);
      return EXIT_FAILURE;                             return EXIT_FAILURE;
   }                                                }

   printf("%s", line);                              printf("%s", line);
   free(line);                                      free(line);
   return EXIT_SUCCESS;                             return EXIT_SUCCESS;
}                                                }
...