c++ 中 iostream 标头的 cout、cerr、clog 有什么区别?何时使用哪一个?

What is the difference between cout, cerr, clog of iostream header in c++? When to use which one?

提问人:Arlene Batada 提问时间:5/27/2013 最后编辑:Kashif Faraz ShamsiArlene Batada 更新时间:6/24/2022 访问量:90761

问:

我试着在互联网上研究 和 之间的区别,但找不到完美的答案。我仍然不清楚何时使用哪个。谁能通过简单的程序向我解释并说明何时使用哪一个的完美情况?coutcerrclog

我访问了这个网站,它显示了一个小程序,但是在那里获得的输出也可以使用。所以,我对每个人的确切用途感到困惑。cerrclogcout

C++ IOSTREAM

评论

7赞 chris 5/27/2013
每个流都有一个计算机识别的流 , (for ),并且默认情况下使用。我相信只是一个缓冲的变化。stdoutstdincinstderrclogcerr

答:

155赞 Some programmer dude #1

通常,用于正常输出、错误和“日志记录”(这可能意味着您希望它的任何含义)。std::coutstd::cerrstd::clog

主要区别在于它不像其他两个那样缓冲。std::cerr


相对于旧的 C 和 ,对应于 ,而 和 两者都对应(除了缓冲)。stdoutstderrstd::coutstdoutstd::cerrstd::clogstderrstd::clog

评论

0赞 void.pointer 8/11/2017
我已经读到也输出到 .那么基于此,你选择哪一个呢?如果通常用于“日志记录”,为什么我希望它进入错误流?日志看起来更像是“普通日志”(又名错误)。clogcerrclogcout
0赞 Some programmer dude 8/11/2017
@void.pointer 正如我在回答中所说,两者都使用标准的“错误”输出,但被缓冲,这可能就是它看起来更像 .选择哪一个进行错误输出?我想这取决于我无法列出的原因,并且必须根据具体情况来决定。cerrclogclogcout
8赞 simplename 4/4/2018
“缓冲”是什么意思?
11赞 Some programmer dude 4/5/2018
@simplename 输出不是直接写入的,而是存储在缓冲区中,直到刷新缓冲区。从历史上看,输出到文件或终端的速度很慢(终端或控制台仍然很慢),逐个字符写入是无效的,写入一大块字节更有效。
3赞 8/7/2021
上下文:Cerr 没有缓冲,因为如果程序以非正常方式崩溃,您可能会在缓冲区中保留有用的调试信息,而不是打印到 stderr。
69赞 riv 5/27/2013 #2

stdout并且是不同的流,即使默认情况下它们都引用控制台输出。重定向(管道)其中一个(例如)不会影响另一个。stderrprogram.exe >out.txt

通常,应用于实际程序输出,而所有信息和错误消息都应打印到 ,以便如果用户将输出重定向到文件,信息消息仍打印在屏幕上,而不是输出文件。stdoutstderr

12赞 David 6/7/2015 #3
  • 使用 cout 作为标准输出。
  • 使用 cerr 显示错误。
  • 使用 clog 进行日志记录。

评论

7赞 Chen Li 5/19/2018
错了,cerr 比 cout 慢,因为没有缓冲!就像 write vs printf 一样
1赞 Kashif Faraz Shamsi 8/10/2017 #4

coutclog 都是缓冲的,但 cerr 是未缓冲的,所有这些都是预定义的对象,它们是 ostream 类的实例。 这三者的基本用途是 cout 用于标准输出,而 clogcerr 用于显示错误。 cerr 未缓冲的主要原因可能是因为假设缓冲区中有多个输出,并且代码中提到了错误异常,那么您需要立即显示该错误,这可以通过 cerr 有效地完成。

如果我错了,请纠正我。

28赞 roottraveller 9/12/2017 #5

标准输出流 (cout):是类的实例。 用于在标准输出设备(通常是显示屏)上产生输出。需要在屏幕上显示的数据使用插入运算符 () 插入到标准输出流 () 中。coutostreamcoutcout<<

未缓冲标准错误流 (cerr):是用于输出错误的标准错误流。这也是该类的一个实例。As 是 un-buffered,因此当我们需要立即显示错误消息时使用它。它没有任何缓冲区来存储错误消息并在以后显示。cerrostreamcerr

缓冲标准错误流(堵塞):这也是类的一个实例,用于显示错误,但与错误不同的是,它首先插入缓冲区并存储在缓冲区中,直到它未完全填充。ostreamcerr

延伸阅读:basic-input-output-c

评论

2赞 Gabriel Staples 10/23/2020
until it is not fully filled.--这不应该说吗?until it IS fully filled
4赞 Gabriel Staples 12/20/2021
仅供参考:看起来 TutorialsPoint.com 直接抄袭了你的答案,在这里。我在 2020 年 10 月 23 日向 TutorialsPoint 发送了关于可能抄袭的电子邮件,他们于 2020 年 10 月 25 日回复说:“当然,加布里埃尔,我们会调查的。在那之后,我再也没有收到他们的回复,但似乎他们没有调查过。
1赞 Christian Hujer 11/29/2022
TutorialsPoint.com 上的剽窃仍然存在。这有什么法律依据?
12赞 leoleol 11/1/2017 #6

这 3 个流的区别在于缓冲。

  1. 使用 cerr 时,输出刷新
    • 立即(因为 CERR 不使用缓冲液)。
  2. 堵塞时,输出冲洗
    • 完成当前功能后。
    • 显式调用函数 flush。
  3. 使用 cout 时,输出会刷新
    • 在调用任何输出流(cout、cerr、clog)之后。
    • 完成当前功能后。
    • 显式调用函数 flush。

请检查以下代码,并通过 3 行运行 DEBUG:f(std::clog)、f(std::cerr)、f(std::out),然后打开 3 个输出文件以查看发生了什么。您可以交换这 3 行,看看会发生什么。

#include <iostream>
#include <fstream>
#include <string>

void f(std::ostream &os)
{
    std::cin.clear(); // clear EOF flags
    std::cin.seekg(0, std::cin.beg); // seek to begin

    std::string line;
    while(std::getline(std::cin, line))   //input from the file in.txt
        os << line << "\n";   //output to the file out.txt
}

void test()
{
    std::ifstream in("in.txt");
    std::ofstream out("out.txt"), err("err.txt"), log("log.txt");
    std::streambuf *cinbuf = std::cin.rdbuf(), *coutbuf = std::cout.rdbuf(), *cerrbuf = std::cerr.rdbuf(),
                    *clogbuf = std::clog.rdbuf();

    std::cin.rdbuf(in.rdbuf()); //redirect std::cin to in.txt!
    std::cout.rdbuf(out.rdbuf()); //redirect std::cout to out.txt!
    std::cerr.rdbuf(err.rdbuf());
    std::clog.rdbuf(log.rdbuf());


    f(std::clog);
    f(std::cerr);
    f(std::cout);

    std::cin.rdbuf(cinbuf);
    std::cout.rdbuf(coutbuf);
    std::cerr.rdbuf(cerrbuf);
    std::clog.rdbuf(clogbuf);
}

int main()
{
    test();
    std::cout << "123";
}
6赞 Tony Delroy 2/26/2018 #7

来自 C++17 标准文档草案:

30.4.3 窄流对象 [narrow.stream.objects]

istream cin;

1 该对象控制来自与该对象关联的流缓冲区的输入,在 (30.11.1) 中声明。cinstdin<cstdio>

2 对象初始化后,返回 .否则,其状态与 (30.5.5.2) 的要求相同。cincin.tie()&coutbasic_ios<char>::init

ostream cout;

3 对象控制输出到与对象关联的流缓冲区,在 (30.11.1) 中声明。coutstdout<cstdio>

ostream cerr;

4 对象控制输出到与对象关联的流缓冲区,在 (30.11.1) 中声明。cerrstderr<cstdio>

5 对象初始化后,为非零并返回 .否则,其状态与 (30.5.5.2) 的要求相同。cerrcerr.flags() & unitbufcerr.tie()&coutbasic_ios<char>::init

ostream clog;

6 对象控制输出到与对象关联的流缓冲区,在 (30.11.1) 中声明。clogstderr<cstdio>

讨论。。。

cout 写入 stdout;CERRCLOGSTDERR

标准输出 () 旨在接收来自程序的无错误、非诊断输出,例如成功处理的输出,可以显示给最终用户或流式传输到某个进一步的处理阶段。stdout

标准错误 () 用于诊断输出,例如警告和错误消息,指示程序尚未或可能未生成用户可能期望的输出。例如,即使输出数据通过管道传递到进一步的处理阶段,也可以将其显示给最终用户,或者可以将其重定向到日志文件。stderr

CINCERRCOUT 相关联

它们都会在自己处理 I/O 操作之前进行刷新。这确保了发送到的提示在程序块读取输入之前是可见的,并且之前的输出在写入错误之前被刷新,当两者都被定向到同一个终端/文件/等时,这将使消息按其生成的时间顺序保持。coutcoutcincoutcerr

这与 - 如果您在那里写入,它不会被缓冲并且不与任何内容绑定,因此它将在刷新之前缓冲相当数量的日志记录。这会产生最高的消息吞吐量,但这意味着即使错误被写入并且位于屏幕上或日志中,这些消息可能无法快速被阅读终端或跟踪日志的潜在消费者看到。clogcerr