C++中的cout、cerr、clog使用及说明

 更新时间:2025年09月18日 15:42:46   作者:MzKyle  
C++中cout、cerr、clog均为输出流对象,区别在于缓冲机制:cout有缓冲,用于常规输出;cerr无缓冲,立即显示错误信息;clog有缓冲,适合日志记录,选择时需根据场景,注意性能和线程安全问题

在C++编程里,coutcerrclog是标准库提供的重要输出流对象,在数据输出方面发挥着关键作用。

一、cout:标准输出流

coutstd::ostream 类的对象,其作用是向标准输出设备(一般是控制台)输出数据。它和 C 语言中的 printf 函数类似,但 cout 具有类型安全和运算符重载的优势,使用起来更加方便。

1. 基本用法

借助 << 运算符,能把各种类型的数据输出到 cout

#include <iostream>
using namespace std;

int main() {
    int num = 42;
    double pi = 3.14159;
    string name = "Alice";

    cout << "Hello, World!" << endl;
    cout << "Number: " << num << endl;
    cout << "Pi: " << pi << endl;
    cout << "Name: " << name << endl;

    return 0;
}

输出结果如下:

Hello, World!
Number: 42
Pi: 3.14159
Name: Alice

2. 格式化输出

通过操纵符(如 setwsetprecision 等)或者成员函数(像 width()precision()),可以对输出格式进行控制。

#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    double value = 123.456789;

    // 设置宽度和填充字符
    cout << setw(10) << setfill('*') << 42 << endl;  // 输出:********42

    // 设置精度
    cout << fixed << setprecision(3) << value << endl;  // 输出:123.457

    // 科学计数法
    cout << scientific << value << endl;  // 输出:1.234568e+02

    // 布尔值以文字形式输出
    cout << boolalpha << true << endl;  // 输出:true

    return 0;
}

3. 链式输出

<< 运算符返回的是对 cout 对象的引用,所以可以进行链式输出。

int a = 10, b = 20;
cout << "a = " << a << ", b = " << b << endl;  // 输出:a = 10, b = 20

4. 重定向输出

可以利用 rdbuf() 函数对 cout 的输出缓冲区进行重定向。

#include <iostream>
#include <fstream>
using namespace std;

int main() {
    ofstream file("output.txt");
    streambuf* oldBuf = cout.rdbuf();  // 保存原来的缓冲区

    cout.rdbuf(file.rdbuf());  // 将输出重定向到文件
    cout << "This will be written to the file." << endl;

    cout.rdbuf(oldBuf);  // 恢复原来的输出
    cout << "This will be written to the console." << endl;

    file.close();
    return 0;
}

二、cerr:标准错误流

cerr 同样是 std::ostream 类的对象,它专门用于输出错误信息。和 cout 的主要区别在于,cerr 的输出是不经过缓冲的,会立即显示在终端上。

1. 基本用法

当程序出现错误时,可使用 cerr 输出错误信息。

#include <iostream>
using namespace std;

int main() {
    ifstream file("nonexistent.txt");
    if (!file.is_open()) {
        cerr << "Error: Could not open file!" << endl;
        return 1;
    }

    // 其他操作
    return 0;
}

2. 无缓冲特性

cerr 的输出不会被缓冲,这在需要立即显示错误信息的场景下非常重要。

// 模拟一个长时间运行的进程
for (int i = 0; i < 1000000; ++i) {
    if (i % 100000 == 0) {
        cerr << "Processing iteration " << i << endl;  // 立即显示
    }
    // 处理逻辑
}

3. 重定向错误输出

cout 一样,cerr 的输出也能被重定向。

ofstream errorFile("errors.log");
streambuf* oldBuf = cerr.rdbuf();
cerr.rdbuf(errorFile.rdbuf());

cerr << "This error will be logged to errors.log" << endl;

cerr.rdbuf(oldBuf);  // 恢复

三、clog:标准日志流

clog 也是 std::ostream 类的对象,用于输出日志信息。它和 cerr 的区别在于,clog 的输出是经过缓冲的。

1. 基本用法

clog 适用于记录程序的执行状态等日志信息。

#include <iostream>
using namespace std;

void log(const string& message) {
    clog << "[LOG] " << message << endl;
}

int main() {
    log("Starting application...");
    
    // 程序逻辑
    
    log("Application terminated successfully.");
    return 0;
}

2. 缓冲特性

clog 的输出会先被存储在缓冲区中,直到缓冲区满或者遇到刷新操作。

clog << "This is a log message.";  // 可能不会立即显示
clog << flush;  // 手动刷新缓冲区

3. 日志重定向

同样可以对 clog 的输出进行重定向。

ofstream logFile("app.log");
clog.rdbuf(logFile.rdbuf());

clog << "Logging to file..." << endl;  // 写入文件

四、三者的对比与选择

特性coutcerrclog
缓冲机制有缓冲无缓冲有缓冲
默认输出目标标准输出标准错误标准错误
典型应用场景普通程序输出错误信息日志记录
是否可重定向

选择建议:

  • 当需要输出程序的正常结果时,应使用 cout
  • 遇到错误情况,需要立即显示错误信息时,要使用 cerr
  • 进行程序调试或者记录执行状态等日志操作时,适合使用 clog

五、高级应用场景

1. 自定义流缓冲区

可以通过继承 streambuf 类来创建自定义的流缓冲区。

class MyBuffer : public streambuf {
protected:
    int overflow(int c) override { //override C++11 特性,显式声明该函数重写基类的虚函数,提高代码安全性
        if (c != traits_type::eof()) { //获取流特性中定义的 EOF(文件结束符)值
            // 自定义处理逻辑
            cout << "*" << static_cast<char>(c) << "*";
        }
        return traits_type::not_eof(c);
    }
};

// 使用自定义缓冲区
MyBuffer buf;
ostream customOut(&buf);
customOut << "Test" << endl;  // 输出:*T*e*s*t*

2. 多线程环境下的输出

在多线程环境中使用输出流时,需要进行同步操作,以避免输出混乱。

#include <iostream>
#include <mutex>
#include <thread>
using namespace std;

mutex coutMutex;

void worker(int id) {
    lock_guard<mutex> lock(coutMutex);
    cout << "Thread " << id << " is working." << endl;
}

int main() {
    thread t1(worker, 1);
    thread t2(worker, 2);

    t1.join();
    t2.join();
    return 0;
}

3. 结合 RAII 管理流重定向

利用 RAII(资源获取即初始化)技术,可以更安全地管理流重定向。

class StreamRedirect {
public:
    StreamRedirect(ostream& stream, streambuf* newBuf)
        : stream(stream), oldBuf(stream.rdbuf()) {
        stream.rdbuf(newBuf);
    }

    ~StreamRedirect() {
        stream.rdbuf(oldBuf);
    }

private:
    ostream& stream;
    streambuf* oldBuf;
};

// 使用示例
ofstream file("output.txt");
{
    StreamRedirect redirect(cout, file.rdbuf());
    cout << "Redirected output" << endl;  // 写入文件
}  // 离开作用域时自动恢复

六、注意事项

性能考量

  • 无缓冲的输出(如 cerr)会带来一定的性能开销,所以在性能敏感的场景中应当谨慎使用。
  • 有缓冲的输出(如 coutclog)在频繁刷新缓冲区时,也可能会影响性能。

线程安全

  • 标准输出流本身并不是线程安全的,在多线程环境下使用时需要进行同步处理。

资源管理

  • 重定向流缓冲区后,要确保在适当的时候恢复原来的缓冲区。

七、总结

  • cout:是最常用的输出流,适用于普通的程序输出,输出内容会被缓冲。
  • cerr:主要用于输出错误信息,输出不会被缓冲,能保证错误信息立即显示。
  • clog:适用于记录日志,输出会被缓冲,有助于提高性能。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • vs2022项目文件夹内.vs文件夹容量虚高问题的解决

    vs2022项目文件夹内.vs文件夹容量虚高问题的解决

    经常会发现VS的项目文件夹占用空间很大,本文主要介绍了vs2022项目文件夹内.vs文件夹容量虚高问题的解决,具有一定的参考价值,感兴趣的可以了解一下
    2023-09-09
  • Qt带参数的信号和槽函数举例详解

    Qt带参数的信号和槽函数举例详解

    信号槽的设计旨在实现控件和处理逻辑的解耦合,但在实际开发中,一对一的关系更为常见,这篇文章主要介绍了Qt带参数的信号和槽函数的相关资料,需要的朋友可以参考下
    2025-03-03
  • 教你用C语言实现三子棋

    教你用C语言实现三子棋

    这篇文章主要为大家详细介绍了C语言实现简单三子棋程序,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • C/C++实现快速排序(两种方式)图文详解

    C/C++实现快速排序(两种方式)图文详解

    这篇文章主要介绍了C/C++实现快速排序的方法,这几天在找工作,被问到快速排序,结果想不出来快速排序怎么弄的;回来搜索了一下,现在记录下来,方便以后查看
    2021-08-08
  • 解析C/C++值传递和址传递的区别

    解析C/C++值传递和址传递的区别

    今天通过本文给大家介绍C/C++值传递和址传递的区别讲解,本文通过实例代码图文相结合给大家介绍的非常详细,需要的朋友参考下吧
    2021-10-10
  • C语言内嵌汇编API内存搜索引擎实例

    C语言内嵌汇编API内存搜索引擎实例

    这篇文章主要介绍了C语言内嵌汇编API内存搜索引擎实例,涉及汇编语言与内存相关操作,需要的朋友可以参考下
    2014-10-10
  • c++中stack、queue和vector的基本操作示例

    c++中stack、queue和vector的基本操作示例

    这篇文章主要给大家介绍了关于c++中stack、queue和vector基本操作的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面跟着小编来一起学习学习吧。
    2017-08-08
  • Sublime Text 3 实现C++代码的编译和运行示例

    Sublime Text 3 实现C++代码的编译和运行示例

    下面小编就为大家带来一篇Sublime Text 3 实现C++代码的编译和运行示例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-09-09
  • c++ sqlite3如何利用事务(BEGIN;COMMIT;)批量操作

    c++ sqlite3如何利用事务(BEGIN;COMMIT;)批量操作

    这篇文章主要介绍了c++ sqlite3如何利用事务(BEGIN;COMMIT;)批量操作,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • C/C++线程退出的四种方法小结

    C/C++线程退出的四种方法小结

    本文主要介绍了C/C++线程退出的四种方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07

最新评论