【问题标题】:Are stdin and stdout actually the same file?标准输入和标准输出实际上是同一个文件吗?
【发布时间】:2018-07-26 07:07:03
【问题描述】:

我完全糊涂了,stdin、stdout 和 stderr 是否有可能在内部指向同一个文件描述符? 因为如果我使用标准输入作为输入或标准输出,如果我想从控制台读取字符串,这在 C 中没有任何区别。

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

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

【问题讨论】:

    标签: c linux stdout stdin io-redirection


    【解决方案1】:

    当输入来自控制台,输出到控制台时,这三个确实碰巧引用了同一个文件。 (但控制台设备的读写实现完全不同。)

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

    <inputfile myprogram >outputfile
    

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

    【讨论】:

    • 好的,所以在我的情况下,它们指向同一个文件,但是如果我向标准输出写入内容,它会如何工作,它也会自动在标准输入和标准错误中,但我以后如何识别它是否进入例如 stderr 管道?
    • 如果我用 write() 写入标准输入并且标准输入映射到我的键盘,那不会崩溃吗?
    • 什么管道?控制台设备在读取或写入时执行不同的操作。
    • 但是如果 stdin 和 stdout 引用同一个文件,那么这在内部如何工作?
    • 控制台设备在这两种情况下都是同一个设备,但read()write()的实现不同。
    【解决方案2】:

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

        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

    要使用stdinstdoutstderrFILE*,您需要改用fread

    【讨论】:

    • 在我的程序中,我使用 0,1 作为输入,我只在那里输入标准输入标准输出以进行抽象
    • @Fernadiniho 你应该在你的问题中明确指出stdinstdout 是在stdio.h 中定义的标识符,通常包含在几乎每个C 控制台程序中。
    【解决方案3】:

    stdin、stdout 和 stderr 是否有可能在内部指向同一个文件描述符?

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

    具有execve(2)-d 您的可执行文件的程序(通常,但不总是,一些shell)可能调用dup2(2) 来共享(即复制)一些文件描述符。

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

    注意STDOUT_FILENO 中的read(2) 可能会失败(例如errno(3)EBADF)在标准输出 可读的(常见)情况下(例如在redirection 之后贝壳)。如果从控制台读取,它可能是可读的。另请阅读the Tty Demystified

    【讨论】:

      【解决方案4】:

      没有什么禁止任何数量的文件句柄在内核中引用相同的东西。

      终端程序的默认设置是让STDINSTDOUTSTDERR 指向同一个终端。

      所以,看起来你使用哪个并不重要,但如果调用者执行任何句柄重定向,这一切都会出错,这很常见。
      最常见的是将一个程序的输出通过管道传输到下一个程序的输入,但不使用 stdout。

      shell 示例:

      source | filter | sink
      

      【讨论】:

        【解决方案5】:

        loginxterm 等程序通常会在创建新的终端会话时打开 tty 设备一次,然后重复 em> 两次或三次文件描述符,安排文件描述符 0、1 和 2 链接到打开的 tty 设备的打开文件描述。它们通常在执行 shell 之前关闭所有其他文件描述符。因此,如果 shell 或其子进程没有进行进一步的重定向,文件描述符 0、1 和 2 将保持链接到同一个文件。因为底层 tty 设备是以读写模式打开的,所以三个文件描述符都有读写权限。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2017-01-19
          • 2018-04-01
          • 2021-10-20
          • 2013-09-18
          • 1970-01-01
          • 2013-06-13
          • 2012-03-16
          • 1970-01-01
          相关资源
          最近更新 更多