【问题标题】:not understanding stdout semantics不理解标准输出语义
【发布时间】:2012-01-11 19:37:30
【问题描述】:

这里是新手!

我下面的程序试图在 Linux 中表现得像(一点点)cat 命令。

  1. 如果没有提供参数,那么它会从用户那里获取输入并在屏幕上打印。(对于一个非常简单的场景,输入缓冲区假定为 10)..

  2. 如果我传递多个参数它正在工作..即它按照程序一一显示不同文件的内容..

--现在的重点是,当我在 shell 上发出命令时:

./mycat abc.txt > 测试

mycat 是我的程序名称,abc.txt 是所需文件,我将其重定向到新文件测试。 我无法理解的奇怪部分是,在重定向之后,如果我查看文件测试,它首先显示来自文件 abc.txt 的数据,然后是我在 c 程序中的 printf 函数,而不是显示 printfs,然后是数据。这是什么原因?

int main(int argc,char *argv[])
{
    char buf[10]; 
    int x,read_bytes,i,fd;
    read_bytes=1;
    char read_buf[1024*1024];

    for(i=0;i<argc;i++)
         printf("you entered  %s\n",argv[i]); //this printf

    switch(argc)
    {
    case 1:
         x=read(0,buf,sizeof(buf));
         write(1,buf,x);
         break;

    default:
         for(i=1;i<argc;i++)
         {
             printf("showing the %dth file\n\n",i);
             fd=open(argv[i], O_RDONLY);
             if(fd==-1)
             {
                 perror("no file opened for such name");
                 exit(1);
             }
             while(read_bytes!=0)
             {
                 read_bytes=read(fd,read_buf,sizeof(read_buf));
                 if(read_bytes==-1)
                 {
                     perror("not able to read\n");
                     exit(2);
                 }
                 write(1,read_buf,read_bytes);
             }
             read_bytes=1;
             close(fd);
         }
         break;
     }

     return 0;
}

【问题讨论】:

  • 有什么理由使用 Posix read/write 而不是更便携和易于消化的标准 C fread/fwrite
  • 你应该尽量减少缩进的创意。
  • 为什么“没有为这样的名称打开文件”?这是一个特别无用的错误消息。只需执行 perror(argv[ i ]) 并告诉用户哪个文件有问题。
  • @kerrek SB-实际上我想知道“原始”和“缓冲”输入输出机制,不同函数或系统调用所花费的时间,...
  • @saurabh:哦,好的。你注意到有什么不同吗?在进行比较之前,请确保使用最大优化进行编译。

标签: c linux redirect cat


【解决方案1】:

printf 也打印到stdout,其文件描述符为1,因此您将printf 行写入与文件内容相同的输出。

您可能更喜欢将诊断信息写入单独的输出,例如 stderr

fprintf(stderr, "Hello world.\n");

【讨论】:

  • +1 只是为了在您的问题中添加一些内容,您还可以使用 >& 重定向 stdout 和 stderr
【解决方案2】:

其他答案是正确的,但似乎无法解释问题。
printfwrite(1) 都写入标准输出。但是printf 被缓冲,而write 没有。
因此,您使用printf 写入的数据首先进入某个缓冲区,并且仅在操作系统选择时才真正写入。但是,write 写入的数据会直接写入文件。
结果是打印了所有内容,但不是按照您想要的顺序。 printf打印的数据可以写在后面的write写的数据之后。

【讨论】:

  • 所以先生,我可以说::write系统调用使用原始输出方法..它绕过内核缓冲区并直接写入stdout.???
  • write 直接进入内核。 printf 在进入内核之前也使用缓冲区(不是在内核中,而是在用户空间中)。
  • @ugoren-正如我所研究的那样,我知道有两个缓冲区,一个在用户空间,一个在内核空间,只要调用 write 系统调用,就会传输数据仅从用户空间到内核空间缓冲区* .. 并且在其他时刻来自内核缓冲区的数据被写入文件(特定于操作系统),这就是系统调用有时不同步的原因(除非我们指定)
  • 和“printf 使用缓冲区(不是在内核中,而是在用户空间中)”所以先​​生,考虑到这一点并同时查看我的问题,我无法证明我的程序中的错误原因因为 write 系统调用也是从用户空间开始的..
【解决方案3】:

请在每个printf 之后使用fflush(stdout),以便刷新标准输出缓冲区。完成此操作后,printfs 将按照代码的顺序显示。

这是修改后的代码。

int main(int argc,char *argv[])
{
    char buf[10]; 
    int x,read_bytes,i,fd;
    read_bytes=1;
    char read_buf[1024*1024];

    for(i=0;i<argc;i++)
        printf("you entered  %s\n",argv[i]); //this printf
    fflush(stdout);
    switch(argc)
    {
     case 1:
          x=read(0,buf,sizeof(buf));
          write(1,buf,x);
          break;

     default:
          for(i=1;i<argc;i++)
          {
              printf("showing the %dth file\n\n",i);
              fflush(stdout);
              fd=open(argv[i], O_RDONLY);
              if(fd==-1)
              {
                 perror("no file opened for such name");
                 exit(1);
              }
              while(read_bytes!=0)
              {
                 read_bytes=read(fd,read_buf,sizeof(read_buf));
                 if(read_bytes==-1)
                 {
                     perror("not able to read\n");
                     exit(2);
                 }
                 write(1,read_buf,read_bytes);
             }
             read_bytes=1;
             close(fd);
         }
         break;
     }

     return 0;
}

【讨论】:

  • 先生,我试过了,但它不适用于我上面提到的情况......即对于这样的语法 ./mycat wordlist.txt wordlist.txt > abc
  • thnx 先生,刚刚给 fflush() 打了一个电话,它正在按你说的那样工作......你能解释一下在没有 fflush 调用的情况下未确定行为的原因吗? ...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-13
  • 2014-07-22
  • 1970-01-01
  • 2013-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多