认清Linux中标准输入和标准输出的双重含义

按照惯例,UNIX系统shell使用文件描述符0与进程的标准输入(一般是键盘)相关联,文件描述符1与标准输出(一般是显示器)相关联,文件描述符2与标准出错输出(一般是显示器)相关联。

在依从POSIX的应用程序中,幻数0、1、2应当替换成符号常量STDIN_FILENO、STDOUT_FILENO和STDERR_FILENO。这些常量都定义在头文件<unistd.h>中。

一般在教材中不会明确区分,但是我们应注意到标准输入有两层含义:一是指STDIN_FILENO(惯例指定的标准输入设备描述符);另一层含义则是指标准输入设备(如键盘)。同样,标准输出也有两层含义:一是指STDOUT_FILENO(惯例指定的标准输出设备描述符);另一层含义则是指标准输出设备(如显示器)。

scanf函数从标准输入读取内容,我们通常会认为是从键盘读取的。printf函数把内容输出到标准输出,我们通常认为是输出到显示器上。这并没有问题,但前提是“在通常情况下”。

精确地说,scanf函数是从文件描述符STDIN_FILENO(0)所关联的文件中读取,而prinf函数则是输出到文件描述符STDOUT_FILENO(1)所关联的文件中。

如果STDIN_FILENO关联的文件不是键盘,那么scanf就不会从键盘读取内容,同理,如果STDOUT_FILENO关联的文件不是显示器,那么printf也不会将内容输出到显示器。

举例说明(不深究此程序片段意义如何,只为说明上面的叙述而用):

...
int fd[2];
int pid;

pipe(fd);

if((pid = fork()) < 0)
{
    perror("fork");
    exit(1);
}
else if(pid == 0)     /* 子进程 */
{
    close(fd[0]);
    dup2(fd[1], STDOUT_FILENO);
    ...    
}
else                 /* 父进程 */
{
    close(fd[1]);    
    dup2(fd[0], STDIN_FILENO);
    ...
}

子进程中,如果在dup2(fd[1], STDOUT_FILENO); 语句后调用printf函数,那么内容并不会输出到显示器,而是写入了管道中。

父进程中,如果在dup2(fd[0], STDIN_FILENO); 语句后调用scanf函数,那么不会从键盘读取内容,而是从管道中读取。

清楚地了解标准输入和标准输出在特定上下文中的确切含义,有时可以避免不必要的困扰。

posted @ 2014-02-28 12:17  ITtecman  阅读(1866)  评论(0编辑  收藏  举报