控制C++中cout及print输出的评论和回答


论坛的lhslktg朋友发了一个贴 ,大意是说在他的程序里面调用了很多的cout的输出,是否能够使用最快速的方法,使得程序的输出能够定向到一个文件内。我理解这个所谓的快速的方法,就是尽量不要改动原有的程序,至少不要改动程序的内部,而达到这个功能。

有朋友给了一个最好的办法,就是命令输出重定位。假如,应用程序的名称为: testcmd,则可以使用下面的命令:
testcmd >test.log

就把命令中的cout的输出写到文件中去了。
还有的朋友给出了在程序开始增加一句标准输出重打开的语句:

freopen("test.log", "w", stdout)

这样也会把这个语句下面的所有输出都写到test.log文件中去了。

但接着这位朋友又有了新的要求,想既保留原有屏幕的输出,又能写到文件中去。
我给出了下面的方案。

testcmd | tee test.log

这里,tee是UNIX系统中的命令,它就像它的名字一样,充当管道T型接头。将输出分成两个流,一个到test.log中去了,另一个仍然输出到屏幕上去。接着,我给

出了tee的简单的源码实现,是为了在那些没有tee命令的系统上使用的。源码如下:

# include  <stdio.h>

int
main(int argc, char **argv)
{
  FILE *fp;
  int c;

  if ( argc > 1 )  {
    fp = fopen(argv[1], "w");
    if ( fp == NULL )  {
      fprintf(stderr, "%s: can not open <%s>/n", argv[0], argv[1]);
      return -1;
    }
  } else
    fp = stdout;

  while ( (c = fgetc(fp)) != EOF )
    fputc(fp);

  return 0;
}

不料,不知道是不是楼主没有仔细看我的说明,竟然问我怎样使用这段代码。我感觉,上面应该说明的很清楚了,就是把这段程序编译成可执行文件,命令名字叫做tee,或者tee.exe, 然后像上面介绍的那样使用:

testcmd | tee test.log

就把testcmd程序的输出既输出到文件里了,又输出到屏幕上去了。不知道这样说,是否明白了。

到此为止,事情还没完,又有了新的需求。就是说,在原来的程序里,既有cout的输出,又有printf的输出。能不能单独控制这两输出分别到屏幕和不同的文件中去。比如将cout的输出到cout.txt,而将printf输出到printf.out中去。我在跟贴里,给出了控制cout的方法,就是在程序的开始,增加下面的代码:

 1 # include      <iostream>
 2 # include      <fstream>
 3
 4 class dostream : public std::ostream {
 5  public:
 6    dostream() : ofs("cout.txt") {}
 7
 8    template <typename _T>
 9    dostream& operator << (_T& data)  {
10      std::cout << data;
11      ofs << data;
12
13      return *this;
14    }
15
16  private:
17    std::ofstream ofs;
18 };
19
20 dostream dout;
21
22 # define    cout        dout

楼主继续发问:
这个是如何控制cout的输出的?
直接在程序最开始添加会有什么效果呢?

好了,我现在开始解释这段程序:

这里,从第4行开始,设计了dostream类,并继承了ostream类,也就是说它继承了ostream的所有函数功能,别忘了,cout就是ostream的子类对象啊!这个类很简单,就是在构造函数里,打开了一个输出文件cout.txt。既然是要控制cout的输出,也就是要控制cout的<<操作符。所以,从第8行开始定义了一个重载<<的模版函数,因为要对各种类型进行输出重载,所以这里的输出数据类型成为了模版参数。在这个模版函数里面,第10行是按照正常的cout的输出,输出到屏幕上,而第11行则是将输出输出到cout.txt文件中去了。

第20行,定义了dostream的一个对象 dout。
第22行,将cout定义为dout,这样当预处理的时候,会将程序中所有调用cout的地方都替换为dout,也就是都调用了我们新定义的这个dostream类的功能。而这个

主要动能就表现在<<操作符的重载上,从而调用了我们实现的重载的函数,把输出写到屏幕上,也输出到文件中去了。

如果还不明白,我们就从实际的例子来说明。
假如,原来的程序里有一句:

cout << "Hello/n";

当把上面的那段程序包含在程序的开始的时候,就出现下面的情况:
在预处理的时候,会根据上面程序的22行进行宏替换,这样,cout >> "Hello/n" 便被替换为:
dout << "Hello/n";

当编译的时候,这个语句便会使用上面第8行开始定义的模版函数,模版的参数为string,也就是会调用下面的函数:
dostream& operator << (string& data);
这里 data = "Hello/n", 也就是说 dostream& operator << ("Hello");
从而调用10行和11行,就把"Hello"分别输出到屏幕上和文件中了。

另外,下面再给出控制printf输出的方法。类似的给出下面的代码:


# include       <stdio.h>
# include       <stdarg.h>

FILE *ofp;

void
init_printf(void)
{
  ofp = fopen("printf.txt", "w");
  if ( ofp == NULL )   {
    fputs("can not open <printf.txt>/n", stderr);
    exit(-1);
  }
}


int
printf(const char *format, ...)
{
  va_list ap;
  int  rc;

  va_start(ap, format);
  vprintf(format, ap);
  rc = vfprintf(ofp, ap, format);
  va_end(ap);

  return rc;
}

这段代码可以单独编辑为一个源程序文件,比如,printf.c。在原来的程序的开始,增加一句:
init_printf()
然后,使用下面的命令进行编译链接:

cc -o testcmd testcmd.cpp printf.c

testcmd.cpp假设为原来的程序。这样,程序会优先调用printf.c中的函数,也就是我们在上面编写的那个printf,而不会调用标准库里的printf了,也就实现了既输出到屏幕上也输出到文件里的功能了。上面的程序调用了C语言标准库的关于变参函数的方法和技巧,如果不太明白,请参考相关书籍。

 

  • 5
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值