日期:2014-05-16  浏览次数:20690 次

dup2后的奇异现象
我写了这样一个程序:
C/C++ code
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main( )
{
  int fd = open("file", O_CREAT|O_WRONLY, 0644);
  int newfd = dup(1);
  dup2(fd, 1);
  close(fd);
  printf("hello\n");
  dup2(newfd, 1);
  printf("world\n");
  return 0;
}

本来期待程序运行时会把"hello\n"写入到文件file中,把"world\n"输出到屏幕上,但结果却是都在屏幕上。如果没有倒数第四行的dup2函数调用,就会都写入到文件file中。
跟踪系统调用的结果发现两个printf的输出的字符串内容被合在一起调用的write。也就是说,printf遇到\n并没有清缓冲。
但更奇怪的问题在于,只要在main函数中第一个dup2调用之前的任何一行插入一个printf调用,后面的输出就不会合并,而是像我先前预期的那样把"hello\n"写入到文件file中,把"world\n"输出到屏幕上了。

求高手解惑!

环境:ubuntu和fedora都是如此。

------解决方案--------------------
怀疑是标准输出重定向到文件中之后,缓冲方式由原来的行缓冲变为了全缓冲
------解决方案--------------------
C/C++ code
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

        int main( )
        {
                printf("start\n");
                  int fd = open("file", O_CREAT|O_WRONLY, 0644);
                    int newfd = dup(1);
                          dup2(fd, 1);
                            close(fd);
                  
                                printf("hello\n");
                                    dup2(newfd, 1);
                                          printf("world\n");
                                            return 0;
        }

------解决方案--------------------
C/C++ code
 When the first I/O operation  occurs
       on a file, malloc(3) is called, and a buffer is obtained.  If a stream refers to a terminal (as stdout normally does) it is line buffered.  The standard
       error stream stderr is always unbuffered by default.

------解决方案--------------------
楼上正确, , 
应该是由行缓冲变为了全缓冲。
验证如下:
至于你说的在第二个dup2前加个printf的话,hello 输出到文件,world输出到屏幕 的事。。 我试验了仍然是都输出到屏幕 。使用的环境是ubuntu 12.04 LTS. 
理解这个行缓冲和全缓冲就行了。 不用太纠缠于太细节的东西 , 因为有些是和实现有关的。 若标准未规定, 则和各自的实现有关 (glibc库的实现)
C/C++ code

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

int main( )
{
  int fd = open("file", O_CREAT|O_WRONLY, 0644);
  int newfd = dup(1);
  dup2(fd, 1);
  close(fd);
  setlinebuf(stdout);
  printf("hello\n");
  dup2(newfd, 1);
  printf("world\n");
  return 0;
}