深入C++库分析sync_with_stdio实现
关于sync_with_stdio(false)
sync_with_stdio(false)具备的基本特性:
- 在C++中sync_with_stdio(false)是一种提升cin、cout效率的手段。
- 尽量在使用cin、cout前调用sync_with_stdio(false),因为cin、cout的特性在调用sync_with_stdio(false)前后有一定变化。
- 调用sync_with_stdio(false)后,scanf()、printf()和cin、cout混用将存在输入/输出顺序与调用顺序不一致。
- sync_with_stdio(false)属于不可逆操作。
透过C++源码,认识sync_with_stdio()
为了一探sync_with_stdio()中深刻的奥秘,索性去找了一份C++库的源码:
- std::ios::sync_with_stdio(false)属于不可逆操作,调用sync_with_stdio(false)后,cin、cout与stdin、stdout之间解锁同步,再次调用sync_with_stdio(false/true)均不生效。stdin、stdout是C库中的标准输入和标准输出,C库中诸如prinf()、putchar()、puts()等接口都是对接stdout,scanf()、getchar()、gets()等接口都是对接stdin,和stdin、stdout对接的设备一般也称之为终端设备,终端设备向下可以和串口、网络、内存或文件等对接,对接怎样的硬件设备,输入输出就将在哪里进行。
- sync_with_stdio(false)的核心动作在于解锁cin、cout和stdin、stdout之间的同步关系,为cin、cout、cerr、clog重新分配缓冲区,如果在C++中开启了宽字符,还将为wcin、wcout、wcerr、wclog执行类似动作。scanf()、printf()和cin、cout为保持同步是公用了同一buf(终端设备缓冲),访问共同的终端设备,以此保证scanf()、printf()和cin、cout混用,输入输出顺序与调用顺序一致。
使用sync_with_stdio(false)后的效果
使用sync_with_stdio(false)后有两点感受很明显:
- cin、cout效率提升明显。
- cout行缓冲特性。
关于cout行缓冲,默认cout与stdout绑定在一起,cout不具备buf的管理权(buf管理权在终端设备),每次使用cout输出的内容都会直接交给stdout对应的设备,这种情况下cout行缓冲不生效。调用sync_with_stdio(false)后,cout具有自管理的buf,使用cout输出不会立即显示,都暂存在buf中,当输出达到一定长度时会将此前输出的内容显示出来,显示内容的容量由cout缓冲buf的大小决定,或者主动调用flush(),亦或者在cout结束添加endl(因为endl操作中包含了flush()),Windows和Linux上的C++都有这个特性。
调用sync_with_stdio(false)后,cin、cout直接访问终端设备,cin效率与scanf()基本一致,cout效率与printf()基本一致。在运行代码时感受到cin、cout更高,也仅仅是C++上层处理数据的策略不同,部分应该是得益于C++的缓冲技术,输入输出的数据都会在C++自管理的buf中转一圈在到上层应用或到底层设备。
看一段C++官方对于sync_with_stdio的描述:
输入输出结构
未执行sync_with_stdio(false),输入输出自上而下结构:
执行sync_with_stdio(false)后,输入输出自上而下结构: