输入输出+Buffer
竞赛用法
ios::sync_with_stdio(false);
cin.tie(nullptr);
缓冲类型
C Buffer
缓冲结构 File*
FILE *stdin;
FILE *stdout;
struct FILE {
char* buffer; // 指向缓冲区的指针
int buf_size; // 缓冲区大小
int pos; // 当前读/写位置
int mode; // 读 / 写 / 行缓冲 / 全缓冲
int fd; // 文件描述符(和内核交互)
};
函数
进缓冲区 ➡ 触发刷新 ➡ “交付”
scanf():数据先进 stdin 缓冲区,遇到回车,才“交付”给程序printf():输出时,数据先进 stdio 缓冲区,触发刷新条件,才真正输出到屏幕3。
C++ Buffer
缓冲结构 cout
ostream cout
│
├── streambuf* sb ← 关键!真正存数据的是 streambuf
│ └── char buffer[...]
│
└── 格式控制 / 类型系统
C++ I/O 的核心是 std::basic_streambuf,它负责真正的数据缓冲与指针管理 4。
// streambuf 的三指针模型
buffer memory:
┌------------------------------─┐
│ gptr pptr epptr │
└------------------------------─┘
gptrget pointer(读指针)pptrput pointer(写指针)epptrend put pointer(写区尾)
注意:这里的读写,均是以程序为主体而言的。
机制
pptr == epptr:gptr == epptr- 当前
buffer已读空 - 调用
read()从内核 再读一批4 - 覆盖整个
buffer
- 当前
epptr = buffer_begin + buffer_size- 即
buffer起始地址 +buffer容量 - 通常大小为 4KB/8KB
- 即
pptr和gptr怎么移动的呢:- 都是从前往后读写
- 并非脑子里想的“同时+共用”:
- 输入流:只用
gptr - 输出流:只用
pptr - 同一个
streambuf不会同时读写
- 输入流:只用
函数
进缓冲区 ➡ 触发刷新 ➡ “交付”
cout:data存入buffer,pptr向前移动,触发才调用write()cin:read()拿数据填满buffer,gptr向前移动
C / C++ Buffer 同步
空间结构
C++ 的 streambuf 绑定到 C 的 FILE 缓冲
cout.streambuf
⬇
stdout.FILE.buffer
函数
-
ios::sync_with_stdio(false):- 和
stdio的缓冲区解绑,不同步,可节省同步开销; - 关闭后禁止混用 printf / cout 6
- 和
-
cin.tie()nullptr:解绑,免得输入前都要cout.flush(),可节省刷新开销;&cout:绑定,适用于需要立即显示输出的情况7。
-
刷新方式
cout >> flush; cout.flush(); cout >> endl; // endl == '\n' + flush // 开启/关闭 每次输出后自动刷新 std::unitbuf std::nounitbuf
I/O 开销分类
I/O 总开销
├── ① 同步开销(synchronization)
├── ② 刷新开销(flush)
├── ③ 系统调用开销(syscall)
└── ④ 用户态处理开销(format / locale / 类型)
参考资料(References)
-
Kernighan, Ritchie — The C Programming Language, 2nd Edition ↩