std :: endl vs \ n

Многие книги по C ++ содержат пример такого кода ...

std::cout << "Test line" << std::endl;

... так что я тоже всегда так поступал. Но вместо этого я видел много кода от работающих разработчиков:

std::cout << "Test line\n";

Есть ли техническая причина предпочесть одно другому или это просто вопрос стиля кодирования?


person Head Geek    schedule 17.10.2008    source источник


Ответы (12)


Различные символы окончания строки не имеют значения, если файл открыт в текстовом режиме, что вы и получите, если не попросите двоичный файл. Скомпилированная программа напишет то, что нужно для компилируемой системы.

Единственное отличие состоит в том, что std::endl очищает выходной буфер, а '\n' - нет ' т. Если вы не хотите, чтобы буфер часто очищался, используйте '\n'. Если да (например, если вы хотите получить весь вывод, а программа работает нестабильно), используйте std::endl.

person David Thornley    schedule 17.10.2008
comment
Или рассмотрите возможность использования ::std::cerr вместо ::std::cout, поскольку он не буферизуется и сбрасывается при каждой операции вывода. - person Omnifarious; 23.01.2010
comment
@Omnifarious: std :: cerr не должен быть зарезервирован для ошибок. Два потока не синхронизируются вместе, поэтому, если вы выводите какой-либо текст в cout, он может быть буферизован, и cerr перейдет прямо к выходу, что приведет к отображению смешанного режима. Используйте cerr для того, для чего он должен быть (ошибки), и cout для того, для чего он предназначен (нормальное взаимодействие). - person Martin York; 03.02.2010
comment
@ Мартин Йорк, я согласен, ::std::cerr для этого. Но, на мой взгляд, если у вас есть код, в котором вы не хотите буферизоваться, гораздо более вероятно, что ваш вывод принадлежит ::std::cerr. Я не могу придумать какой-либо веской причины регулярно отказываться от буферизации для ::std::cout. - person Omnifarious; 04.02.2010
comment
std :: endl тоже поддерживает платформу, нет? - person Lucas; 17.02.2010
comment
@Lucas: Платформа поддерживает не более чем '\ n'. - person CB Bailey; 17.02.2010
comment
@LokiAstari: Я бы не сказал, что stderr предназначен для ошибок. Скорее, это для внеполосных диагностических сообщений, если хотите. Должна быть возможность сказать ./prog > file и сохранить только истинную полезную нагрузку программы, но программа может захотеть вывести гораздо больше информации о состоянии, даже при нормальном взаимодействии. - person Kerrek SB; 28.11.2011
comment
Во многих реализациях стандартный вывод буферизуется по строкам, и запись '\ n' в любом случае вызывает сброс, если не было выполнено std :: cout.sync_with_stdio (false). скопировано отсюда - person GuLearn; 14.08.2013
comment
@Omnifarious, пожалуйста, не помещайте весь вывод в cerr. Печать только ошибок в cerr позволяет затем разделить два выходных потока, перенаправив их в разные места. Если я перенаправляю cerr вывод с помощью 2>/dev/null, я не хочу, чтобы весь мой обычный вывод тоже исчезал. Точно так же, если я перенаправляю весь свой обычный вывод в файл типа 1>output.txt, я хочу, чтобы весь вывод был без ошибок. Или, если я перенаправляю его на grep или more, я хочу, чтобы канал проталкивал cout материал, как и ожидалось, а затем передавал ошибки, выполняя 3>&1 1>&2 2>&3 | grep Поэтому, пожалуйста, не смешивайте их. Всегда. - person Cory-G; 01.07.2014
comment
@Omnifarious: хорошая причина для регулярного отказа от буферизации заключается в том, что вы хотите, чтобы ваш вывод был доступен во время записи, а не в какое-то неопределенное время в будущем. Но обычно вы хотите, чтобы буферизация происходила, когда вы пишете часть вывода. - person ; 15.09.2015
comment
Также есть ostream :: flush - person Braden Best; 27.09.2016
comment
'\ n' также сбрасывается, если вывод подключен к интерактивному устройству, например терминалу. - person Emily L.; 18.01.2018
comment
Я вижу, что многие люди говорят «flush», но все, что делает ostream :: flush, - это вызов sync () для нижележащего streambuf, поэтому то, что происходит, полностью зависит от реализации streambuf. Например, fstream использует filebuf, поэтому эффект будет en.cppreference.com/ w / cpp / io / basic_filebuf / sync; Также вызывается en.cppreference.com/w/cpp/io/ios_base/sync_with_stdio или нет кажется довольно важным, и никто (кроме GuLearn) даже не упоминает об этом: / - person Carlo Wood; 27.02.2019
comment
Обратите внимание: stdout буферизируется только по строке, если он считается интерактивным, он полностью буферизуется, если не интерактивный - см. stackoverflow.com/questions/5229096/. - person studgeek; 25.01.2021

Разницу можно проиллюстрировать следующим:

std::cout << std::endl;

эквивалентно

std::cout << '\n' << std::flush;

So,

  • Используйте std::endl, если хотите принудительно выполнить немедленную очистку вывода.
  • Используйте \n, если вас беспокоит производительность (что, вероятно, не так, если вы используете оператор <<).

Я использую \n в большинстве строк.
Затем используйте std::endl в конце абзаца (но это просто привычка и обычно не требуется).

Вопреки другим утверждениям, символ \n отображается на правильную платформу в конце последовательности строк только в том случае, если поток идет в файл (std::cin и std::cout являются специальными, но по-прежнему являются файлами (или подобными файлам)).

person Martin York    schedule 17.10.2008
comment
Во многих случаях немедленное отображение вывода является отвлекающим маневром, поскольку cout привязан к cin, а это означает, что если вы читаете ввод из cin, cout будет сброшен первым. Но если вы хотите отобразить индикатор выполнения или что-то еще, не читая из cin, тогда, конечно, очистка полезна. - person Chris Jester-Young; 30.03.2011
comment
@LokiAstari: если вы используете оператор ‹<, вы, вероятно, не беспокоитесь о производительности - почему? Я не знал, что operator<< неэффективен, или какую альтернативу использовать для повышения производительности? Пожалуйста, укажите мне какой-нибудь материал, чтобы понять это дальше. - person legends2k; 22.01.2014
comment
@ legends2k: Есть старая сказка жен о том, что потоки C ++ не так производительны, как printf () в C. Хотя до некоторой степени это правда, основная разница в скорости вызвана тем, что люди неправильно используют потоки C ++. stackoverflow.com/a/1042121/14065 В C ++ не забудьте несинхронизировать iostreams с C-потоками sync_with_stdio(false) и не сбрасывать выводить непрерывно. Пусть библиотека решит, когда это делать. stackoverflow.com/a/1926432/14065 - person Martin York; 22.01.2014
comment
@Loki: Есть городская легенда, что sync_with_stdio делает iostreams так же быстро, как stdio. Не работает - person Ben Voigt; 15.09.2015
comment
@BenVoigt: Я был осторожен со своей формулировкой выше (так что я им доволен). Он не такой производительный, как stdio (потому что он делает больше). НО многие люди жалуются на провалы в производительности, вызванные синхронизацией со stdio. - person Martin York; 15.09.2015

Могут быть проблемы с производительностью, std::endl принудительно очищает выходной поток.

person Martin Beckett    schedule 17.10.2008
comment
И он может выполнять любую другую обработку, которая требуется локальной системе для правильной работы. - person dmckee --- ex-moderator kitten; 18.10.2008

Там подразумевается другой вызов функции, если вы собираетесь использовать std::endl

a) std::cout << "Hello\n";
b) std::cout << "Hello" << std::endl;

а) один раз вызывает оператора <<.
б) дважды вызывает оператора <<.

person Nathan    schedule 17.11.2009
comment
Это может быть очевидно, но имеет огромное влияние на многопоточные программы, где, как правило, первая версия будет записывать одну строку за один снимок, а вторая версия может быть разделена записями из других потоков. Достаточно часто я пишу std :: cout ‹< hello \ n ‹< std :: flush, чтобы избежать этого. - person smparkes; 23.06.2011
comment
А что насчет std::cout << "Hello" << "\n";? - person byxor; 22.02.2018
comment
@byxor Почти то же самое, за исключением очистки буфера, как описано в других ответах. В любом случае, когда вы можете объединить два строковых литерала в один, это будет лишним. - person iBug; 19.04.2018
comment
Что ж, если печатаемая строка не является литералом, тогда вызовы << также будут равны 2 в случае a, поэтому я бы не стал утверждать необходимость одного или двух << ( или два вызова функций вообще) быть разницей между \n и endl. - person Enlico; 22.11.2018
comment
Лол, нет, я использую \ n не по этой причине. - person Carlo Wood; 27.02.2019

Я вспомнил, что читал об этом в стандарте, так вот:

См. Стандарт C11, который определяет, как ведут себя стандартные потоки, поскольку программы C ++ взаимодействуют с CRT, стандарт C11 должен управлять здесь политикой очистки.

ИСО / МЭК 9899: 201x

7.21.3 §7

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

7.21.3 §3

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

Это означает, что std::cout и std::cin полностью буферизуются, если и только если они относятся к неинтерактивному устройству. Другими словами, если к терминалу подключен stdout, разницы в поведении нет.

Однако, если вызывается std::cout.sync_with_stdio(false), '\n' не вызовет сброса даже на интерактивные устройства. В противном случае '\n' эквивалентно std::endl, если не выполняется конвейерная обработка файлов: c ++ ref на std :: endl.

person Emily L.    schedule 29.08.2014

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

person Ferruccio    schedule 17.10.2008

Ничего страшного, но endl не работает в boost :: lambda.

(cout<<_1<<endl)(3); //error

(cout<<_1<<"\n")(3); //OK , prints 3
person Özgür    schedule 22.02.2009

Если вы используете Qt и endl, вы можете случайно в конечном итоге использовать неправильный endl, что даст вам очень неожиданные результаты. См. Следующий фрагмент кода:

#include <iostream>
#include <QtCore/QtCore> 
#include <QtGui/QtGui>

// notice that there is no "using namespace std;"
int main(int argc, char** argv)
{
    QApplication qapp(argc,argv);
    QMainWindow mw;
    mw.show();
    std::cout << "Finished Execution!" << endl;
    // This prints something similar to: "Finished Execution!67006AB4"
    return qapp.exec();
}

Обратите внимание, что я написал endl вместо std::endl (что было бы правильно) и, очевидно, есть функция endl, определенная в qtextstream.h (которая является частью QtCore).

Использование "\n" вместо endl полностью обходит любые потенциальные проблемы с пространством имен. Это также хороший пример того, почему размещение символов в глобальном пространстве имен (как это делает Qt по умолчанию) - плохая идея.

person smerlin    schedule 17.02.2010
comment
Ух! Кто бы хотел быть using namespace std; ?? :-) - person Steve Folly; 17.02.2010
comment
Противный. Спасибо за комментарий, я уверен, что другие столкнутся с этим. - person Head Geek; 25.02.2010
comment
@SteveFolly Я знаю. Почему нет? - person ʇolɐǝz ǝɥʇ qoq; 21.03.2015
comment
@ ʇolɐǝzǝɥʇqoq Это нормально, если вы не делаете этого в файлах заголовков. - person smerlin; 31.03.2015
comment
@ ʇolɐǝzǝɥʇqoq Пожалуйста, избегайте using namespace std;. Это считается плохой практикой. См. Почему «using namespace std;» считается плохой практикой? - person L. F.; 22.07.2019

У меня всегда была привычка использовать просто std :: endl, потому что мне это легко увидеть.

person Zee JollyRoger    schedule 17.10.2008

Манипулятор std::endl эквивалентен '\n'. Но std::endl всегда сбрасывает поток.

std::cout << "Test line" << std::endl; // with flush
std::cout << "Test line\n"; // no flush
person Community    schedule 24.05.2019

Если вы собираетесь запускать свою программу на чем-нибудь еще, кроме своего портативного компьютера, никогда не используйте оператор endl. Особенно, если вы пишете много коротких строк или как я часто видел отдельные символы в файле. Использование endl известно для уничтожения сетевых файловых систем, таких как NFS.

person John Damm Sørensen    schedule 27.10.2018
comment
Это из-за промывки? Я понимаю, как это возможно. - person Head Geek; 29.10.2018
comment
@Head В самом деле. Я также видел, как это снижает производительность ввода-вывода диска. - person sbi; 05.02.2019

С справкой Это ввод-вывод только для вывода манипулятор.

std::endl Вставляет символ новой строки в выходную последовательность os и сбрасывает ее, как будто вызывая os.put(os.widen('\n')), за которым следует os.flush().

Когда использовать:

Этот манипулятор можно использовать для немедленного получения строки вывода,

например,

при отображении вывода из долго выполняющегося процесса, регистрации активности нескольких потоков или регистрации активности программы, которая может неожиданно завершиться сбоем.

Также

Явный сброс std :: cout также необходим перед вызовом std :: system, если порожденный процесс выполняет какой-либо экранный ввод-вывод. В большинстве других обычных сценариев интерактивного ввода-вывода std :: endl является избыточным при использовании с std :: cout, потому что любой ввод из std :: cin, вывод на std :: cerr или завершение программы вызывает вызов std :: cout .промывать(). Использование std :: endl вместо '\ n', рекомендованное некоторыми источниками, может значительно снизить производительность вывода.

person Kaleem Ullah    schedule 27.03.2018