C ++: «std :: endl» против «\ n»

470

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

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

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

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

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

  • 4
    Хорошее объяснение: cppkid.wordpress.com/2008/08/27/why-i-prefer-n-to-stdendl
  • 0
    возможный дубликат "\ n" или '\ n' или std :: endl в std :: cout?
Показать ещё 2 комментария
Теги:
coding-style
iostream
c++-faq

12 ответов

405
Лучший ответ

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

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

  • 21
    Или рассмотрите возможность использования ::std::cerr вместо ::std::cout поскольку он небуферизован и сбрасывается при каждой операции вывода.
  • 128
    @ Omnifarious: нет std :: cerr должно быть зарезервировано для ошибок. Два потока не синхронизируются вместе, поэтому, если вы выводите некоторый текст в cout, он может быть буферизован, и cerr перейдет непосредственно к выводу, что приведет к отображению в смешанном режиме. Используйте cerr для того, для чего он предназначен (ошибки), и cout для того, для чего он предназначен (нормальное взаимодействие).
Показать ещё 10 комментариев
201

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

std::cout << std::endl;

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

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

Итак,

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

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

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

  • 5
    Во многих случаях «видеть вывод немедленно» является красной сельдью, поскольку cout привязан к cin , что означает, что если вы читаете ввод из cin , cout будет сброшен первым. Но если вы хотите отобразить индикатор выполнения или что-то без чтения из cin , тогда, конечно, очистка полезна.
  • 8
    @LokiAstari: если вы используете оператор <<, вы, вероятно, не беспокоитесь о производительности - почему? Я не знал, что operator<< не работает, или какую альтернативу использовать для производительности? Пожалуйста, укажите мне некоторые материалы, чтобы понять это дальше.
Показать ещё 3 комментария
42

Возможны проблемы с производительностью, std::endl заставляет поток потока вывода.

  • 1
    И он может выполнять любую другую обработку, которая требуется локальной системе, чтобы эта работа работала хорошо.
24

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

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

ISO/IEC 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, если не передать сообщения в файлы: С++ ref на std:: endl.

22

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

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

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

  • 17
    Это может быть очевидно, но это оказывает огромное влияние на многопоточные программы, где, как правило, первая версия будет записывать одну строку в одном кадре, где вторая версия может быть разделена записью из других потоков. Довольно часто я пишу std :: cout << "hello \ n" << std :: flush, чтобы избежать этого.
  • 0
    Как насчет std::cout << "Hello" << "\n"; ?
Показать ещё 3 комментария
18

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

11

Неважно, но endl не будет работать в boost:: лямбда.

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

(cout<<_1<<"\n")(3); //OK , prints 3
9

Если вы используете Qt и endl, вы случайно можете использовать неправильный endl, со мной случилось сегодня, и я был как..WTF??

#include <iostream>
#include <QtCore/QtCore> 
#include <QtGui/QtGui>
//notice that i dont have a "using namespace std;"
int main(int argc, char** argv)
{
    QApplication qapp(argc,argv);
    QMainWindow mw;
    mw.show();
    std::cout << "Finished Execution !" << endl << "...";
    // Line above printed: "Finished Execution !67006AB4..."
    return qapp.exec();
}

Конечно, это была моя ошибка, так как я должен был написать std::endl, , но если вы используете endl, qt и using namespace std;, это зависит от порядка включенных файлов, если правильный endl будет использоваться. *

Конечно, вы могли бы перекомпилировать Qt для использования пространства имен, поэтому вы получите ошибку компиляции для приведенного выше примера.

EDIT: Забыл отметить, что Qt endl объявлен в "qtextstream.h", который является частью QtCore

* EDIT2: С++ выберет правильный endl, если у вас есть using для std::cout или пространства имен std, так как std::endl находится в том же пространстве имен, что и std::cout, механизм ADL С++ будет выберите std::endl.

  • 28
    Urgh! Кто бы хотел using namespace std; ?? :-)
  • 2
    Насти. Спасибо за комментарий, я уверен, что другие столкнутся с этим.
Показать ещё 2 комментария
2

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

1

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

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', которое поощряется некоторыми источниками, может значительно ухудшить производительность вывода.

0

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

  • 0
    Это из-за промывки? Я вижу, как это возможно.
  • 0
    @Head Действительно. Я также видел, как это сказалось на производительности дискового ввода-вывода.
-19

Если вы не заметили, endl походит на нажатие клавиши ENTER, а "\n" похоже на нажатие ENTER KEY + SPACE BAR.

  • 13
    совершенно неправильно.
  • 5
    это нонсенс.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню