stdin和stdout实际上是同一文件吗?

时间:2018-07-26 07:07:04

标签: c linux stdout stdin io-redirection

我完全感到困惑,stdin,stdout和stderr是否可能在内部指向相同的filedescriptor? 因为如果我要使用stdin作为输入或stdout来从控制台读取字符串,则在C中没有区别。

read(1, buf, 200)read(0, buf, 200)一样工作,这怎么可能?

({0 == STDIN_FILENO == fileno(stdin)
1 == STDOUT_FILENO == fileno(stdout)

5 个答案:

答案 0 :(得分:4)

当输入来自控制台,而输出进入控制台时,这三个确实确实指向了同一文件。 (但是控制台设备在读写方面有非常不同的实现。)

无论如何,您应仅将stdin / stdout / stderr用于其预期目的;否则,将无法进行以下重定向:

<inputfile myprogram >outputfile

(这里stdinstdout指的是两个不同的文件,而stderr指的是控制台。)

答案 1 :(得分:2)

某些人似乎忽略的一件事:read是低级系统调用。它的第一个参数是Unix文件描述符,而不是像FILE*stdinstdout这样的stderr。您应该收到有关此的编译器警告:

    warning: passing argument 1 of ‘read’ makes integer from pointer without a cast [-Wint-conversion]
   int r = read(stdout, buf, 200);
                ^~~~~~

在我的系统上,它不适用于stdinstdoutread始终返回-1,并且errno设置为EBADF,即“错误文件描述符”。在我看来,这些确切的行在您的系统上似乎不太可能:指针必须指向内存地址0、1或2,这在典型的计算机上不会发生。

要使用read,您需要将其传递给STDIN_FILENOSTDOUT_FILENOSTDERR_FILENO

要使用FILE*stdinstdout之类的stderr,则需要使用fread

答案 2 :(得分:1)

  

stdin,stdout和stderr是否有可能在内部指向相同的文件描述符?

file descriptor是您process的文件描述符表的索引(另请参见credentials(7) ...)。根据定义,STDIN_FILENO为0,STDOUT_FILENO为1,而STDERR_FILENO为2。阅读有关proc(5)的信息以查询有关某个进程的信息(例如,尝试ls -l /proc/$$/fd在您的交互式外壳中)。

具有shell-d可执行文件的程序(通常但并非总是某些execve(2))可能已经调用dup2(2)来共享(即重复)一些文件描述符。

另请参阅fork(2)intro(2)并阅读一些Linux编程书籍,例如旧的ALP

请注意,在标准输出为 not 的(常见)情况下,来自STDOUT_FILENO的{​​{3}}可能会失败(例如read(2)EBADF)可读(例如在外壳errno(3)之后)。如果从控制台读取,则可能可读。另请参阅redirection

答案 3 :(得分:0)

没有什么可以禁止内核中引用相同内容的任何文件句柄。

终端程序的默认设置是让STDINSTDOUTSTDERR引用同一终端。

因此,使用哪种方法似乎无关紧要,但是如果调用者进行任何句柄重定向,这都会出错,这很常见。
最常见的是将一个程序的输出通过管道传递到下一个程序的输入,但是将stdout排除在外。

shell的示例:

source | filter | sink

答案 4 :(得分:0)

登录 xterm 之类的程序通常在创建新的终端会话时打开tty设备一次,并进行重复文件描述符两次或三次,将文件描述符0、1和2链接到打开的tty设备的打开文件描述。它们通常在执行外壳程序之前关闭所有其他文件描述符。因此,如果外壳程序或其子进程没有进一步的重定向,则文件描述符0、1和2仍链接到同一文件。由于底层tty设备是以读写模式打开的,因此所有三个文件描述符都具有读写访问权限。