В чем разница между cout, cerr, clog заголовка iostream в с ++? Когда использовать какой?

104

Я пытался исследовать разницу между cout, cerrи clogв Интернете , но не мог найти идеальный ответ. Я до сих пор не понимаю, когда использовать. Может ли кто-нибудь объяснить мне с помощью простых программ и проиллюстрировать идеальную ситуацию, когда использовать какую?

Я посетил этот сайт, который показывает небольшую программу на cerrи clog, но результат, полученный там, также можно получить с помощью cout. Итак, я запутался в точном использовании каждого из них.

Арлин Батада
источник
6
У каждого из них есть поток, распознаваемый компьютером stdout, stdin(для cin), stderrкоторый он использует по умолчанию. Я считаю, что clogэто просто cerrс изменением буферизации.
Крис

Ответы:

52

stdoutи stderrявляются разными потоками, хотя по умолчанию они оба относятся к выходу консоли. Перенаправление (соединение) одного из них (например program.exe >out.txt) не повлияет на другой.

Как правило, его stdoutследует использовать для фактического вывода программы, в то время как вся информация и сообщения об ошибках должны быть распечатаны stderr, чтобы, если пользователь перенаправляет вывод в файл, информационные сообщения по-прежнему выводились на экран, а не в выходной файл.

riv
источник
132

Обычно вы используете std::coutдля нормального вывода, std::cerrдля ошибок и std::clogдля «ведения журнала» (что может означать все, что вы хотите).

Основное отличие состоит в том, что std::cerrон не буферизуется, как два других.


По отношению к старому C stdoutи stderr, std::coutсоответствует stdout, в то время как std::cerrи std::clogобе соответствует stderr( за исключением того, что std::clogв буфер).

Какой-то чувак-программист
источник
Я читал, что clogтакже выводит на cerr. Итак, исходя из этого, какой из них вы выберете? Если clogэто обычно для «ведения журнала», почему я должен отправлять его в поток ошибок? Журналы больше похожи на «обычные журналы» (иначе cout), чем на ошибки.
void.pointer
@ void.pointer Как я уже сказал в своем ответе, оба cerrи clogиспользуют стандартный вывод «ошибок», но clogбуферизуются, что может быть поэтому больше похоже cout. Какой выбрать для вывода ошибок? Зависит, я полагаю, по большему количеству причин, чем я могу перечислить, и это нужно решать от случая к случаю.
Какой-то чувак-программист
3
что вы имеете в виду под «буферизованным»?
simplename
6
@simplename Вывод не записывается напрямую, он сохраняется в буфере, пока буфер не будет очищен . Вывод в файл или терминал исторически выполняется медленно (терминалы или консоли по-прежнему работают медленно), посимвольная запись неэффективна, запись блока байтов намного эффективнее.
Какой-то чувак-программист
16

Стандартный выходной поток (cout): cout это экземпляр ostreamкласса. coutиспользуется для вывода на стандартное устройство вывода, которым обычно является экран дисплея. Данные, необходимые для отображения на экране, вставляются в стандартный поток вывода ( cout) с помощью оператора вставки ( <<).

Небуферизованный стандартный поток ошибок (cerr): cerr стандартный поток ошибок, который используется для вывода ошибок. Это тоже экземпляр ostreamкласса. Поскольку cerrон не буферизован, он используется, когда нам нужно немедленно отобразить сообщение об ошибке. У него нет буфера для хранения сообщения об ошибке и последующего отображения.

Буферизованный стандартный поток ошибок (clog): это также экземпляр ostreamкласса и используется для отображения ошибок, но в отличие cerrот ошибки сначала вставляется в буфер и сохраняется в буфере до тех пор, пока он не будет полностью заполнен.

дальнейшее чтение: базовый-ввод-вывод-c

roottraveller
источник
until it is not fully filled.- разве это не говорит until it IS fully filled?
Габриэль Стейплс,
11

Отличие этих трех потоков в буферизации.

  1. С cerr вывод сбрасывается
    • немедленно (потому что cerr не использует буфер).
  2. При засорении выход промывает
    • после того, как вы закончите свою текущую функцию.
    • явно вызвать функцию flush.
  3. С cout вывод сбрасывается
    • после вызова любых выходных потоков (cout, cerr, clog).
    • после того, как вы закончите свою текущую функцию.
    • явно вызвать функцию flush.

Проверьте следующий код и запустите DEBUG через 3 строки: f (std :: clog), f (std :: cerr), f (std :: out), затем откройте 3 выходных файла, чтобы увидеть, что произошло. Вы можете поменять местами эти 3 строки, чтобы увидеть, что произойдет.

#include <iostream>
#include <fstream>
#include <string>

void f(std::ostream &os)
{
    std::cin.clear(); // clear EOF flags
    std::cin.seekg(0, std::cin.beg); // seek to begin

    std::string line;
    while(std::getline(std::cin, line))   //input from the file in.txt
        os << line << "\n";   //output to the file out.txt
}

void test()
{
    std::ifstream in("in.txt");
    std::ofstream out("out.txt"), err("err.txt"), log("log.txt");
    std::streambuf *cinbuf = std::cin.rdbuf(), *coutbuf = std::cout.rdbuf(), *cerrbuf = std::cerr.rdbuf(),
                    *clogbuf = std::clog.rdbuf();

    std::cin.rdbuf(in.rdbuf()); //redirect std::cin to in.txt!
    std::cout.rdbuf(out.rdbuf()); //redirect std::cout to out.txt!
    std::cerr.rdbuf(err.rdbuf());
    std::clog.rdbuf(log.rdbuf());


    f(std::clog);
    f(std::cerr);
    f(std::cout);

    std::cin.rdbuf(cinbuf);
    std::cout.rdbuf(coutbuf);
    std::cerr.rdbuf(cerrbuf);
    std::clog.rdbuf(clogbuf);
}

int main()
{
    test();
    std::cout << "123";
}
Duc-Viet Ha
источник
10
  • Используйте cout для стандартного вывода.
  • Используйте cerr для отображения ошибок.
  • Используйте засорение для регистрации.
Дэвид Варгас
источник
6
Неправильно, cerr работает медленнее, чем cout из-за отсутствия буфера! Точно так же, как write vs printf
陳 力
4

Из черновика стандартного документа C ++ 17:

30.4.3 Узкие объекты потока [thin.stream.objects]

istream cin;

1 Объект cinуправляет вводом из буфера потока, связанного с объектом stdin, объявленным в <cstdio>(30.11.1).

2 После cinинициализации объекта cin.tie()возвращается &cout. В остальном его состояние такое же, как требуется для basic_ios<char>::init(30.5.5.2).

ostream cout;

3 Объект coutуправляет выводом в буфер потока, связанный с объектом stdout, объявленным в <cstdio>(30.11.1).

ostream cerr;

4 Объект cerrуправляет выводом в буфер потока, связанный с объектом stderr, объявленным в <cstdio>(30.11.1).

5 После cerrинициализации объекта cerr.flags() & unitbufненулевое значение и cerr.tie()возвращается &cout. В остальном его состояние такое же, как требуется для basic_ios<char>::init(30.5.5.2).

ostream clog;

6 Объект clogуправляет выводом в буфер потока, связанный с объектом stderr, объявленным в <cstdio>(30.11.1).

Обсуждение ...

coutпишет в stdout; cerrи clogчтобыstderr

Стандартный выход ( stdout) предназначен для получения не содержащих ошибок, недиагностических выходных данных из программы, таких как выходные данные успешной обработки, которые могут быть отображены конечному пользователю или переданы на какой-либо дальнейший этап обработки.

Стандартная ошибка ( stderr) предназначена для диагностического вывода, такого как предупреждения и сообщения об ошибках, которые указывают на то, что программа не выдала или, возможно, не выдала вывод, который мог бы ожидать пользователь. Этот ввод может отображаться для конечного пользователя, даже если выходные данные передаются на этап дальнейшей обработки.

cinи cerrпривязаны кcout

Оба они сбрасываются coutперед обработкой самих операций ввода-вывода. Это гарантирует, что отправляемые приглашения coutбудут видны до того, как программа будет блокирована для чтения ввода cin, и что предыдущий вывод coutбудет сброшен перед записью ошибки cerr, что сохраняет сообщения в хронологическом порядке их генерации, когда оба направлены на один и тот же терминал / файл / так далее..

Это контрастирует с тем, что clogесли вы напишете там, он не будет буферизован и ни к чему не привязан, поэтому он будет буферизовать приличный объем журналов перед сбросом. Это обеспечивает наивысшую пропускную способность сообщений, но означает, что сообщения могут не быть быстро видимыми для потенциального потребителя, читающего терминал или заканчивающего журнал.

Тони Делрой
источник
1

И cout, и clog буферизуются, но cerr не буферизуется, и все это предопределенные объекты, которые являются экземплярами класса ostream. Базовое использование этих трех: cout используется для стандартного ввода, тогда как clog и cerr используются для отображения ошибок. Основная причина, по которой cerr не буферизуется, может заключаться в том, что предположим, что у вас есть несколько выходных данных в буфере и в коде упоминается исключение ошибки, тогда вам необходимо немедленно отобразить эту ошибку, что может быть эффективно выполнено с помощью cerr .

Пожалуйста, поправьте меня, если я ошибаюсь.

Кашиф Фараз Шамси
источник