C++常见标准输入输出流

文章主要介绍了C++标准IO库中的输出工具cout、cerr、clog。cout写到标准输出,经缓冲后输出,可重定向;cerr输出到标准错误,不缓冲,常用于迅速输出出错信息,一般不重定向;clog也输出标准错误流,信息存于缓冲区,满或遇endl时输出。还给出示例说明重定向情况。

文章转载自https://blog.youkuaiyun.com/qq_38556370/article/details/80640845

之前一直在用,但就是没在意两者到底有啥却别,今天又想到这个问题,总结下吧(以下的内容均是本人从网上查阅资料看来整理的,暂时还没有查阅官方资料,不保证准确,欢迎讨论)

其实大家平常常会用的主要有三个:cout、cerr、clog,首先简单介绍下三者。

这三者在C++中都是标准IO库中提供的输出工具(至于有关的重载问题在此不讨论):

cout:写到标准输出的ostream对象;

cerr:输出到标准错误的ostream对象,常用于程序错误信息;

clog:也是输出标准错误流(这点儿和cerr是一样的),貌似平时很少用到这个啊;

 

具体在输出的时候,三者是有区别的:

1、cout经过缓冲后输出,默认情况下是显示器。这是一个被缓冲的输出,是标准输出,并且可以重新定向(关于重新定向的意思可以参考下面的例子);

2、cerr不经过缓冲而直接输出,一般用于迅速输出出错信息,是标准错误,默认情况下被关联到标准输出流,但它不被缓冲,也就说错误消息可以直接发送到显示器,而无需等到缓冲区或者新的换行符时,才被显示。一般情况下不被重定向(重定向这点儿好像有争论。

 

 

对于为什么有cerr和clog

  比如,你的程序遇到调用栈用完了的威胁(无限,没有出口的递归)。

  你说,你到什么地方借内存,存放你的错误信息?

  所以有了cerr。其目的,就是在你最需要它的紧急情况下,还能得到输出功能的支持。

  缓冲区的目的,就是减少刷屏的次数——比如,你的程序输出圣经中的一篇文章。不带缓冲的话,就会每写一个字母,就输出一个字母,然后刷屏。有了缓冲,你将看到若干句子“同时”就出现在了屏幕上(由内存翻新到显存,然后刷新屏幕)。

 

附:

#include <iostream>

using namespace std;

int main()

{

cout << "cout" << endl;

cerr << "cerr" << endl;

return 0;

}

运行此程序之后,我们在命令行执行如下命令:

假设编译运行后的可执行文件名为cerr.exe,其目录为E:\cpro\cerr\Debug\cerr.exe

在命令行下,切换到这个目录下,执行命令:cerr>test.log

命令行输出如下:

E:\cpro\cerr\Debug>cerr>>test2.log

Cerr(这是在命令行下输出的)

查看test2.log文件,发现里面只有

Cout

一行。

可能这个就是所谓的重定向输出。

从这里可以看出:
cout是在终端显示器输出,cout流在内存中对应开辟了一个缓冲区,用来存放流中的数据,当向cout流插入一个endl,不论缓冲区是否漫了,都立即输出流中所有数据,然后插入一个换行符. 

cerr流对象是标准错误流,指定为和显示器关联,和cout作用差不多,有点不同就是cout 
通常是传到显示器输出,但可以被重定向输出到文件,而cerr流中的信息只能在显示器输出. 
clog流也是标准错误流,作用和cerr一样,区别在于cerr不经过缓冲区,直接向显示器输出信息,而clog中的信息存放在缓冲区,缓冲区满或者遇到endl时才输出.

今天看C++Primer(第四版)的时候又看到了这几个,摘抄一段话,供大家参考:

"标准库定义了4个IO对象,处理输入时使用命名为cin的istream类型对象,这个对象也成为标准输入。处理输出时使用命名为cout的ostream类型对象,这个对象也称为标准输出。标准库还定义了另外两个ostream对象,分别命名为cerr和clog。cerr对象又叫标准错误,通常用来输出警告和错误信息给程序的使用者,而clog对象用于产生程序执行的一般信息。一般情况下,系统将这些对象与执行窗口联系起来,这样,当我们从cin读入时,数据从执行程序的窗口读入,当写到cout、cerr、clog时,输出写至同一窗口。运行程序时,大部分操作系统都提供了重定向输入或者输出流的方法。利用重定向可以将这些流与所选择的文件联系起来"

<think>好的,我现在需要回答用户关于C++自定义标准输入输出流的问题。首先,我得回顾一下自己对这方面的了解。C++的流库主要基于iostream,包括cin、cout、cerr和clog,这些是标准输入输出流。用户的问题是关于如何自定义这些流,可能涉及到如何创建用户自己的流对象或者修改现有的流行为。 接下来,我需要确定用户的具体需求。自定义输入输出流可能包括几个方面:比如重载操作符<<和>>,创建自定义的流缓冲区(streambuf),或者使用现有的流机制进行扩展。可能需要分别解释这些方法,并给出示例。 首先,我应该解释标准流的基本概念,然后介绍如何通过重载操作符来自定义类型的输入输出。这部分相对基础,但可能用户已经了解,需要确认是否深入。不过用户的问题可能更偏向于如何创建或定制流本身,而不仅仅是类型的输入输出。 接下来,自定义流缓冲区是关键。因为C++的流操作最终都是通过流缓冲区(streambuf派生类)来处理缓冲和实际的IO操作。所以,要自定义流,通常需要继承streambuf并覆盖其虚函数,如underflow、overflow、sync等。这部分需要详细说明,并提供示例代码。 另外,用户可能想知道如何替换标准流的缓冲区,比如将cout重定向到文件或其他地方。这可以通过rdbuf()方法来实现,例如将cout的缓冲区替换为文件流的缓冲区。这也是一个常见的应用场景,应该包含在回答中。 还需要考虑可能的问题,比如线程安全、缓冲区管理、错误处理等,但作为介绍性内容,可能不需要深入这些细节,但可以提及需要注意的地方。 然后,结构方面,应该分点说明不同的自定义方法,如操作符重载、自定义流类、自定义缓冲区等,每个部分给出简要解释和代码示例。代码示例需要用正确的C++语法,并且注释说明关键点。 可能还需要比较不同的方法适用场景,比如何时使用操作符重载,何时需要自定义streambuf。例如,如果只是希望自定义某个类型的输出格式,重载<<操作符即可;但如果需要改变流的底层行为,比如写入网络或加密数据,则需要自定义流缓冲区。 最后,总结一下各种方法的优缺点,并给出使用建议。确保回答结构清晰,逐步引导用户理解不同层次的自定义方法。</think>在C++中,自定义标准输入输出流主要通过操作流缓冲区(streambuf)和创建自定义流对象实现。以下是三种常见方式的详细说明: 1. **运算符重载(基础定制)** ```cpp struct Point { int x, y; // 输出运算符重载 friend ostream& operator<<(ostream& os, const Point& p) { return os << "(" << p.x << ", " << p.y << ")"; } // 输入运算符重载 friend istream& operator>>(istream& is, Point& p) { char discard; return is >> discard >> p.x >> discard >> p.y >> discard; } }; // 使用示例 Point p; cin >> p; // 输入格式要求:(10, 20) cout << p; // 输出格式:(10, 20) ``` 2. **流缓冲区定制(底层控制)** ```cpp class UpperCaseBuffer : public streambuf { protected: int_type overflow(int_type c) override { if (c != EOF) { c = toupper(c); char ch = c; cout.rdbuf()->sputn(&ch, 1); // 输出到标准cout } return c; } }; // 使用示例 UpperCaseBuffer ubuf; ostream ucout(&ubuf); ucout << "hello"; // 输出HELLO ``` 3. **完整流类定制(高级封装)** ```cpp class ColorStream : public ostream { public: enum Color { RED=31, GREEN=32, BLUE=34 }; ColorStream(ostream& os, Color c) : ostream(os.rdbuf()) { *this << "\033[1;" << c << "m"; } ~ColorStream() { *this << "\033[0m"; } }; // 使用示例 cout << "Normal"; { ColorStream(cout, ColorStream::RED) << "Warning!"; } cout << "Back to normal"; ``` **应用场景对比:** | 方法 | 适用场景 | 性能影响 | 控制粒度 | |-----------------|----------------------------------|----------|--------| | 运算符重载 | 自定义类型的序列化/反序列化 | 低 | 对象级 | | 流缓冲区定制 | 改变底层IO行为(如加密/压缩) | 中 | 字节级 | | 完整流类定制 | 添加流属性(如颜色/日志等级) | 低 | 流级 | **注意事项:** 1. 缓冲区管理需实现`sync()`方法确保数据刷新 2. 多线程环境需要加锁保证原子性 3. 错误状态需正确设置`setstate(failbit)` 4. 本地化设置会影响字符处理(使用imbue()方法) 通过组合这些技术,可以实现日志分级系统、网络流传输、数据加密流等高级功能。例如创建加密输出流: ```cpp class CryptoStream : public ostream { public: CryptoStream(ostream& os, int key) : ostream(new CryptoBuffer(os.rdbuf(), key)) {} ~CryptoStream() { delete rdbuf(); } private: class CryptoBuffer : public streambuf { // 实现加密算法的overflow/underflow方法 }; }; ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值