换行符是否也刷新缓冲区?
Does new line character also flush the buffer?
我知道像 endl
和 \n
之间的区别这样的问题已经在 SO 上回答了很多次。但他们只提到 endl
能够将缓冲区刷新到 stdout
,而 \n
则不能。
所以,我对刷新缓冲区的理解是,给定的输入存储在缓冲区中,并且仅在遇到 endl
或某些显式时才传递到 stdout
flush
函数。如果是这样,我希望以下代码:
#include <iostream>
#include <unistd.h>
int main(void)
{
std::cout << "Hello\nworld";
sleep(2);
std::cout << std::endl;
return 0;
}
显示:
2秒后
Hello
World
但实际输出是:
Hello
2秒后
World
为什么会这样?
不应该 \n
也存储在缓冲区中,只有当遇到 endl
时,缓冲区才会 flushed/displayed 到 stdout
,但是从我的角度来看观察 \n
与 endl
的行为方式相同。
正在将评论转化为答案。
这取决于 cout
的去向。如果它到达一个终端('interactive device'),那么它就不能被完全缓冲——它通常是行缓冲的,这意味着字符出现在一个换行符被打印之后,或者理论上可以是无缓冲的。如果它要传输到管道或文件或其他非交互式目标,endl
会强制输出数据,即使流已完全缓冲,通常也是如此。
I also wanted to know if I provided neither new line character nor endl
, will the output be displayed on the stdout
once it reaches the end of the program, I know it does for terminal, but is it applicable to all types of stdout
?
是的,当文件流在程序的(正常)结束时关闭时,挂起的输出将被刷新。当缓冲区已满时,它也会被刷新。如果程序中止,挂起的输出通常不会被刷新。
标准 C++ 流对象(std::cin
、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
.
行为同步时,它可能会得到它
我知道像 endl
和 \n
之间的区别这样的问题已经在 SO 上回答了很多次。但他们只提到 endl
能够将缓冲区刷新到 stdout
,而 \n
则不能。
所以,我对刷新缓冲区的理解是,给定的输入存储在缓冲区中,并且仅在遇到 endl
或某些显式时才传递到 stdout
flush
函数。如果是这样,我希望以下代码:
#include <iostream>
#include <unistd.h>
int main(void)
{
std::cout << "Hello\nworld";
sleep(2);
std::cout << std::endl;
return 0;
}
显示:
2秒后
Hello
World
但实际输出是:
Hello
2秒后
World
为什么会这样?
不应该 \n
也存储在缓冲区中,只有当遇到 endl
时,缓冲区才会 flushed/displayed 到 stdout
,但是从我的角度来看观察 \n
与 endl
的行为方式相同。
正在将评论转化为答案。
这取决于 cout
的去向。如果它到达一个终端('interactive device'),那么它就不能被完全缓冲——它通常是行缓冲的,这意味着字符出现在一个换行符被打印之后,或者理论上可以是无缓冲的。如果它要传输到管道或文件或其他非交互式目标,endl
会强制输出数据,即使流已完全缓冲,通常也是如此。
I also wanted to know if I provided neither new line character nor
endl
, will the output be displayed on thestdout
once it reaches the end of the program, I know it does for terminal, but is it applicable to all types ofstdout
?
是的,当文件流在程序的(正常)结束时关闭时,挂起的输出将被刷新。当缓冲区已满时,它也会被刷新。如果程序中止,挂起的输出通常不会被刷新。
标准 C++ 流对象(std::cin
、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
.