Символ новой строки также очищает буфер?

Я понимаю, что такие вопросы, как, разница между 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,

Другие вопросы по тегам