Новый символ строки также очищает буфер?
Я понимаю, что такие вопросы, как, разница между endl
и n
были даны ответы много раз на этот вопрос. Но они только упоминают, что endl
способен смывать буфер на stdout
, в то время как n
этого не делает.
Итак, я понимаю под буфером, который сбрасывается, то, что данные входные данные хранятся в буфере и передаются в stdout
только тогда, когда они встречаются с endl
или некоторыми явными функциями flush
. Если да, то я ожидал, что следующий код:
#include <iostream>
#include <unistd.h>
int main(void)
{
std::cout << "Hellonworld";
sleep(2);
std::cout << std::endl;
return 0;
}
К дисплей:
через 2 секунды
Hello
World
Но фактический результат был:
Hello
через 2 секунды
World
Почему это так ?
Не должен n
также храниться в буфере и только когда endl
встречается буфер должен быть смыт/отображен на stdout
, но из того, что я наблюдаю, n
действует так же, как endl
.
2 ответа:
преобразование комментариев в ответ.
Это зависит от того, куда идет
cout
. Если он поступает на терминал ("интерактивное устройство"), то он не может быть полностью буферизован - обычно это буферизация строк, что означает, что символы появляются после печати новой строки или теоретически могут быть не буферизованы. Если он направляется в канал, файл или другое неинтерактивное место назначения,endl
вытесняет данные, даже если поток полностью буферизован, как это обычно бывает.Я также хотел знать, если я не предоставил ни нового символа строки, ни
endl
, будет ли вывод отображаться наstdout
, Как только он достигнет конца программы, я знаю, что это делает для терминала, но применимо ли это ко всем типам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++ не имеет понятия буферизации строк, но он может получить его, когда стандартный ввод-вывод синхронизируется с поведением C
stdout
.