2011-09-29 201 views
1

看看这个代码:哪些错误与此打印顺序

#include<stdio.h> 
#include <unistd.h> 
    int main() 
    { 
      int pipefd[2],n; 
      char buf[100]; 
      if(pipe(pipefd)<0) 
        printf("Pipe error"); 
      printf("\nRead fd:%d write fd:%d\n",pipefd[0],pipefd[1]); 
      if(write(pipefd[1],"Hello Dude!\n",12)!=12) 
        printf("Write error"); 
      if((n=read(pipefd[0],buf,sizeof(buf)))<=0) 
        printf("Read error"); 
      write(1,buf,n); 
      return 0; 
    } 

我期待中的printf要打印阅读fd和之前从管道中读取你好哥们写的FD。但事实并非如此......见here。当我在我们学校的计算机实验室尝试同样的程序我的产量

Read fd:3 write fd:4 
Hello Dude! 

也是我们几个朋友指出,改变printf语句包含更多的\n字符数变化的输出顺序...例如。 printf("\nRead fd:%d\n write fd:%d\n",pipefd[0],pipefd[1]);表示读取fd被打印,然后消息Hello Dude!然后写入fd被打印。这是什么行为? 注意:出实验室使用我们运行终端的Linux服务器,但我不记得编译器版本。

回答

5

这是因为printf到标准输出缓冲,但write到标准输出文件描述符是没有的。

这意味着行为可以根据你有什么样的缓冲来改变。在C中,标准输出为如果可以确定连接到交互式设备,则缓冲。否则它完全缓冲(见here为什么这是如此)。

行缓冲意味着它会在看到换行符时刷新到文件描述符。完全缓冲意味着它只会在缓冲区填满时(例如,4K值的数据)或流关闭时(或者当您使用fflush时)刷新。

当您以交互方式运行它时,冲洗发生在write之前,因为printf遇到\n并自动刷新。 (例如,通过将输出重定向到文件或在线编译器/执行程序,它可能会做同样的事情来捕获数据以供演示),则在之后冲洗发生write(因为printf每行后都不冲洗)。

其实,你并不需要在那里所有的管道东西看到这个动作,按照以下程序:

#include <stdio.h> 
    #include <unistd.h> 
    int main (void) { 
     printf ("Hello\n"); 
     write (1, "Goodbye\n", 8); 
     return 0; 
    } 

当我执行myprog ; echo === ; myprog >myprog.out ; cat myprog.out,我得到:

Hello 
Goodbye 
=== 
Goodbye 
Hello 

,你可以看到不同类型的缓冲所产生的差异。

如果你想行缓冲无论重定向,你可以尝试:

setvbuf (stdin, NULL, _IOLBF, BUFSIZ); 

早在你的程序 - 它的实现定义的实现是否支持此所以它可能没有任何效果,但我从来没见过许多不起作用的地方。

4

您不应该在单个文件描述符上混合调用writeprintf。将write更改为fwrite

使用FILE的功能被缓冲。使用文件描述符的函数不是。这就是为什么你可能会混合订单。

您也可以尝试在write之前致电fflush

1

发生了什么是printf以缓冲方式写入标准输出 - 字符串在输出之前保存在缓冲区中 - 而写入标准输出后的“写入”未缓冲。这可能会导致'write'的输出先出现,如果printf的缓冲区稍后才刷新。

您可以使用fflush()显式刷新 - 但更好的办法不是将缓冲和非缓冲写入混合到同一个输出。在终端上键入man printf,man fflush,man fwrite等,以了解更多关于这些命令的具体含义。

2

当你一次写入同一个文件或管道,或者通过两种方式写入(直接IO和输出流)时,你可以得到这种行为。原因是输出流被缓冲。

With fflush()您可以控制该行为。

+2

嗨glglgl,我被管道分散注意力,忽略那一个:) – ypnos

+0

我的写作'write(1,buf,n)'的意图是打印到控制台 – sasidhar

+0

thx澄清 - 我现在可以删除我的评论:-) – glglgl