【问题标题】:Using FILE *f = stdin;使用 FILE *f = stdin;
【发布时间】:2020-04-14 22:38:12
【问题描述】:

我希望(ed)用 C 语言实现 POSIX tail。如果输入是文件(从 argv 接收的文件名),那么我使用 fseek 来获取文件末尾,因此实现起来很容易。

但是当输入是标准输入时,我不能使用 fseek。我以某种方式发现我可以做到:

FILE *f = stdin;

然后我可以使用 stdin 作为文件和 fseek,一切都按预期工作(只需做一些小工作 :D)。

我的问题只是,这样可以吗?我的意思是(对我来说)像这样使用标准输入有点不寻常。不会有任何“安全”或其他错误吗?我对我的尾巴进行了很多测试,它看起来即使在边缘情况下也能很好地工作。

【问题讨论】:

  • 没关系,这就是处理命名文件或标准输入的程序正常工作的方式。
  • fseek 是否与 stdin 相关?见Using fseek with a file pointer that points to stdin
  • @WeatherVane 如果stdin 被重定向到一个文件,为什么它不相关?
  • 这个问题是关于标准输入到终端的默认连接,但是如果你运行tail < filename,你可以使用fseek()
  • @Barmar 确实没有返回 0在无法搜索的设备上,返回值未定义。

标签: c file stdin tail fseek


【解决方案1】:

这确实是一件奇怪的事情,因为它没有帮助。 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;
}                                                }

【讨论】:

    猜你喜欢
    • 2011-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-19
    • 2012-01-01
    • 2016-07-05
    • 2015-09-18
    相关资源
    最近更新 更多