std::cin
标准 C++ 流对象( 、std::cout
、std::cerr
和)的默认设置std::clog
是它们与相应的 C 流(stdin
、stdout
和stderr
)同步。同步意味着交替访问 C++ 和 C 流会产生一致的行为。例如,此代码应生成字符串hello, world
:
std::cout << "hel";
fprintf(stdout, "lo,");
std::cout << " wo";
fprintf(stdout, "rld");
C++ 标准没有规定如何实现这种同步。实现它的一种方法是禁用std::cout
(和家庭)的任何缓冲并立即访问stdout
. 也就是说,上面的示例可以立即将单个字符写入stdout
.
如果字符实际写入到stdout
默认设置,则将stdout
使用缓冲模式。我在标准中找不到规范,但通常缓冲模式的默认值stdout
是_IOLBF
当它连接到交互式流(例如控制台)时,即在行尾刷新缓冲区。写入文件的默认值通常是_IOFBF
,即在写入完整缓冲区时刷新输出。因此,写入换行符std::cout
可能会导致缓冲区被刷新。
C++ 中的流通常设置为缓冲。也就是说,向文件写入换行符通常不会导致输出立即出现(只有在字符导致缓冲区溢出流设置为无缓冲时才会立即出现)。由于同步stdout
通常是不必要的,例如,当程序总是用于std::cout
写入标准输出,但确实会导致标准输出的输出显着减慢(禁用流的缓冲会使它们变慢),可以禁用同步:
std::ios_base::sync_with_stdio(false);
这会禁用所有流对象的同步。对于一个糟糕的实现,可能没有任何效果,而一个好的实现将启用缓冲,std::cout
从而显着提高速度,并且可能还会禁用行缓冲。
一旦缓冲了 C++ 流,就没有内置方法可以在写入换行符时刷新它。其主要原因是处理行缓冲需要通过流缓冲区检查每个字符,这有效地抑制了对字符的批量操作,从而导致显着减速。如果需要,可以通过一个简单的过滤流缓冲区来实现行缓冲。例如:
class linebuf: public std::streambuf {
std::streambuf* sbuf;
public:
linebuf(std::streambuf* sbuf): sbuf(sbuf) {}
int_type overflow(int_type c) {
int rc = this->sbuf->sputc(c);
this->sbuf->pubsync();
return rc;
}
int sync() { return this->sbuf->pubsync(); }
};
// ...
int main() {
std::ios_base::sync_with_stdio(false);
linebuf sbuf(std::cout.rdbuf());
std::streambuf* origcout = std::cout.rdbuf(&sbuf);
std::cout << "line\nbuffered\n";
std::cout.rdbuf(origcout); // needed for clean-up;
}
tl;dr:C++ 标准没有行缓冲的概念,但是当标准 I/O 与 C 的stdout
.