【问题标题】:How to write to two different places with the same buffer? (C-System call)如何使用相同的缓冲区写入两个不同的地方? (C-系统调用)
【发布时间】:2018-01-31 16:18:08
【问题描述】:

我应该使用 '-a' 标志选项来实现 Unix 'tee' 命令,该选项会将输入附加到 EOF 而不是覆盖它。问题是我只能将 C 系统调用用于 I/O。到目前为止,我已经能够实现除多个输出之外的所有内容。

在我的 while 循环中,我有两条不同的行,一条写入文件,另一条写入标准输出。如果我将其中一个注释掉,或者将一个放在另一个之前,那是可行的,但同时保留两个则不行。只有我首先调用的 write 函数才能工作。我假设是因为如果我理解正确,它会清空缓冲区。

如何将我输入到标准输入的任何内容写入标准输出和文件?

#include "csapp.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char **argv) {

   int aflag = 0;
   int n_char = 0;
   int c,fd;
   char *path;
   char buf;

   opterr = 0;

   // getopt is looking for flags with dashes
   while((c = getopt(argc, argv, "a")) != -1)
      switch (c)
      {
         // assign the aflag value to 1, so we know that arg was applied
         case 'a':
            aflag = 1;
            break;
         case '?':
            if (isprint (optopt))
               fprintf(stderr, "Unknown option \\x%x'.\n",optopt);
            return 1;
         default:
            abort();
      }

   // if the -a flag was provided, we must append, if not overwrite the file
   // by default if the file exists.
   if(aflag == 1) {
      path = argv[2];
      fd = open(path,O_WRONLY|O_APPEND,0);
   } else {
      path = argv[1];
      fd = open(path,O_WRONLY,0);
   }

   // While not EOF, right to stdout and file
   while((n_char=read(STDIN_FILENO, &buf,1)) != 0)
      n_char=write(fd, &buf, 1);
      write(STDOUT_FILENO,&buf,1);
   close(fd);

   return 0;
}

【问题讨论】:

  • 在你的while循环中添加{}并将write都放入其中。如果没有{}while 循环只会执行第一个write
  • 谢谢你的朋友,成功了!

标签: c io buffer system-calls tee


【解决方案1】:

您的while 循环没有{}。因此,它只考虑循环体中的第一条语句:

   while((n_char=read(STDIN_FILENO, &buf,1)) != 0)
      n_char=write(fd, &buf, 1);
      write(STDOUT_FILENO,&buf,1);  <===== this statement is out of loop body

为循环体中的语句块添加{}

   while((n_char=read(STDIN_FILENO, &buf,1)) != 0) {
      n_char=write(fd, &buf, 1);
      write(STDOUT_FILENO,&buf,1);
   }

附加

作为良好编程习惯的一部分,您还应该检查程序中使用的系统调用的返回值,例如write(),并确保进行正确的错误处理。

write:

出错时返回-1,并适当设置errno

【讨论】:

  • 有理由不使用代码块吗?我在教科书中经常看到它,这就是我复制该模式的原因。当我用 Java 编码时,我总是使用它们。只是从语法的角度好奇。
  • 不知道你指的是哪本教材。没有花括号,只有循环定义后面的第一个语句被认为属于循环体,这意味着循环只有一个语句。使用花括号,{} 之间的语句被视为循环体,它可以是单个语句或多个语句。
  • 明白了,总是放花括号是最佳做法吗?我想这就是我要问的。
  • 是的,使用花括号是一种很好的编程习惯。它使代码更易于阅读。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-17
  • 2021-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多