C++---cout、cerr、clog

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

一、cout:标准输出流

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

1. 基本用法

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

cpp 复制代码
#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()),可以对输出格式进行控制。

cpp 复制代码
#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 对象的引用,所以可以进行链式输出。

cpp 复制代码
int a = 10, b = 20;
cout << "a = " << a << ", b = " << b << endl;  // 输出:a = 10, b = 20
4. 重定向输出

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

cpp 复制代码
#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 输出错误信息。

cpp 复制代码
#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 的输出不会被缓冲,这在需要立即显示错误信息的场景下非常重要。

cpp 复制代码
// 模拟一个长时间运行的进程
for (int i = 0; i < 1000000; ++i) {
    if (i % 100000 == 0) {
        cerr << "Processing iteration " << i << endl;  // 立即显示
    }
    // 处理逻辑
}
3. 重定向错误输出

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

cpp 复制代码
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 适用于记录程序的执行状态等日志信息。

cpp 复制代码
#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 的输出会先被存储在缓冲区中,直到缓冲区满或者遇到刷新操作。

cpp 复制代码
clog << "This is a log message.";  // 可能不会立即显示
clog << flush;  // 手动刷新缓冲区
3. 日志重定向

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

cpp 复制代码
ofstream logFile("app.log");
clog.rdbuf(logFile.rdbuf());

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

四、三者的对比与选择

特性 cout cerr clog
缓冲机制 有缓冲 无缓冲 有缓冲
默认输出目标 标准输出 标准错误 标准错误
典型应用场景 普通程序输出 错误信息 日志记录
是否可重定向
选择建议:
  • 当需要输出程序的正常结果时,应使用 cout
  • 遇到错误情况,需要立即显示错误信息时,要使用 cerr
  • 进行程序调试或者记录执行状态等日志操作时,适合使用 clog

五、高级应用场景

1. 自定义流缓冲区

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

cpp 复制代码
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. 多线程环境下的输出

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

cpp 复制代码
#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(资源获取即初始化)技术,可以更安全地管理流重定向。

cpp 复制代码
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;  // 写入文件
}  // 离开作用域时自动恢复

六、注意事项

  1. 性能考量

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

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

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

七、总结

  • cout:是最常用的输出流,适用于普通的程序输出,输出内容会被缓冲。
  • cerr:主要用于输出错误信息,输出不会被缓冲,能保证错误信息立即显示。
  • clog:适用于记录日志,输出会被缓冲,有助于提高性能。
相关推荐
求梦82019 小时前
【力扣hot100题】反转链表(18)
算法·leetcode·职场和发展
智航GIS19 小时前
10.7 pyspider 库入门
开发语言·前端·python
NAGNIP19 小时前
机器学习特征工程中的特征选择
算法·面试
跟着珅聪学java19 小时前
JavaScript 底层原理
java·开发语言
l1t19 小时前
DeepSeek辅助编写的利用位掩码填充唯一候选数方法求解数独SQL
数据库·sql·算法·postgresql
项目題供诗19 小时前
C语言基础(二)
c语言·开发语言
Z1Jxxx19 小时前
反序数反序数
数据结构·c++·算法
副露のmagic19 小时前
更弱智的算法学习 day25
python·学习·算法
求梦82019 小时前
【力扣hot100题】移动零(1)
算法·leetcode·职场和发展
J_liaty19 小时前
RabbitMQ面试题终极指南
开发语言·后端·面试·rabbitmq