我完全感到困惑,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)
)
答案 0 :(得分:4)
当输入来自控制台,而输出进入控制台时,这三个确实确实指向了同一文件。 (但是控制台设备在读写方面有非常不同的实现。)
无论如何,您应仅将stdin / stdout / stderr用于其预期目的;否则,将无法进行以下重定向:
<inputfile myprogram >outputfile
(这里stdin
和stdout
指的是两个不同的文件,而stderr
指的是控制台。)
答案 1 :(得分:2)
某些人似乎忽略的一件事:read
是低级系统调用。它的第一个参数是Unix文件描述符,而不是像FILE*
,stdin
和stdout
这样的stderr
。您应该收到有关此的编译器警告:
warning: passing argument 1 of ‘read’ makes integer from pointer without a cast [-Wint-conversion]
int r = read(stdout, buf, 200);
^~~~~~
在我的系统上,它不适用于stdin
或stdout
。 read
始终返回-1
,并且errno
设置为EBADF
,即“错误文件描述符”。在我看来,这些确切的行在您的系统上似乎不太可能:指针必须指向内存地址0、1或2,这在典型的计算机上不会发生。
要使用read
,您需要将其传递给STDIN_FILENO
,STDOUT_FILENO
或STDERR_FILENO
。
要使用FILE*
,stdin
或stdout
之类的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)
没有什么可以禁止内核中引用相同内容的任何文件句柄。
终端程序的默认设置是让STDIN
,STDOUT
和STDERR
引用同一终端。
因此,使用哪种方法似乎无关紧要,但是如果调用者进行任何句柄重定向,这都会出错,这很常见。
最常见的是将一个程序的输出通过管道传递到下一个程序的输入,但是将stdout排除在外。
shell的示例:
source | filter | sink
答案 4 :(得分:0)
登录和 xterm 之类的程序通常在创建新的终端会话时打开tty设备一次,并进行重复文件描述符两次或三次,将文件描述符0、1和2链接到打开的tty设备的打开文件描述。它们通常在执行外壳程序之前关闭所有其他文件描述符。因此,如果外壳程序或其子进程没有进一步的重定向,则文件描述符0、1和2仍链接到同一文件。由于底层tty设备是以读写模式打开的,因此所有三个文件描述符都具有读写访问权限。