Символ новой строки также очищает буфер?
Я понимаю, что такие вопросы, как, разница между endl
а также \n
много раз отвечали на ТАК. Но они только упоминают, что endl
в состоянии очистить буфер на stdout
, в то время как \n
, не.
Итак, я понимаю, что при очистке буфера заданный ввод сохраняется в буфере и передается в stdout
только когда это сталкивается endl
или какой-то объяснение 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
встреченный буфер должен быть очищен / отображен на 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
,