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


569

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

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

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

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

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


7
Хорошее объяснение: cppkid.wordpress.com/2008/08/27/why-i-prefer-n-to-stdendl


25
@ derobert этот старше другого
Кира

3
@HediNaily действительно так и есть. Но ответ на другой кажется мне немного лучше, поэтому я решил сделать это таким образом. Кроме того, другой немного шире, также охватывает '\n'.
Дероберт

stackoverflow.com/a/30968225/3163618 может быть значительная разница в производительности.
qwr

Ответы:


473

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

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


24
Или рассмотрите возможность использования ::std::cerrвместо, ::std::coutпоскольку он небуферизован и сбрасывается при каждой операции вывода.
Всезнающий

142
@ Omnifarious: нет std :: cerr должно быть зарезервировано для ошибок. Два потока не синхронизируются вместе, поэтому, если вы выводите некоторый текст в cout, он может быть буферизован, и cerr перейдет непосредственно к выводу, что приведет к отображению в смешанном режиме. Используйте cerr для того, для чего он предназначен (ошибки), и cout для того, для чего он предназначен (нормальное взаимодействие).
Мартин Йорк

23
@Lucas: Платформа не знает больше, чем '\ n'.
CB Bailey

32
@LokiAstari: я бы не сказал « stderrза ошибки». Скорее, это для внеполосных диагностических сообщений, если хотите. Должна быть возможность говорить ./prog > fileи хранить только истинную полезную нагрузку программы, но программе может потребоваться выводить гораздо больше информации о состоянии, даже при обычном взаимодействии.
Керрек С.Б.

13
«Во многих реализациях стандартный вывод буферизуется строкой, и запись '\ n' в любом случае вызывает сброс, если только std :: cout.sync_with_stdio (false) не был выполнен." скопировано отсюда
GuLearn

249

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

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, тогда, конечно, очистка полезна.
Крис Шестер-Янг

9
@LokiAstari: если вы используете оператор <<, вы, вероятно, не беспокоитесь о производительности - почему? Я не знал, что operator<<не работает, или какую альтернативу использовать для производительности? Пожалуйста, укажите мне на материал, чтобы понять это дальше.
legends2k

8
@ legends2k: Существует старая история о женах, что потоки C ++ не так производительны, как C printf (). Правда, в некоторой степени основное различие в скорости вызвано тем, что люди неправильно используют потоки C ++. stackoverflow.com/a/1042121/14065 В C ++ не забывайте синхронизировать iostreams с C-потоками sync_with_stdio(false)и не сбрасывать вывод постоянно. Позвольте библиотеке решить, когда это сделать. stackoverflow.com/a/1926432/14065
Мартин Йорк,

6
@Loki: есть городская легенда, которая sync_with_stdioделает iostreams такими же быстрыми, как stdio. Это не
Бен Фойгт

2
@BenVoigt: я был осторожен с моей формулировкой выше (поэтому я счастлив с ними). Это не так эффективно, как STDIO (потому что это делает больше). НО большая разница в производительности, на которую жалуются люди, связана с синхронизацией со stdio.
Мартин Йорк,


30

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

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

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


19
Это может быть очевидно, но это оказывает огромное влияние на многопоточные программы, где, как правило, первая версия будет записывать одну строку в одном кадре, где вторая версия может быть разделена записью из других потоков. Довольно часто я пишу std :: cout << "hello \ n" << std :: flush, чтобы избежать этого.
smparkes

Как насчет std::cout << "Hello" << "\n";?
byxor

1
@byxor Почти то же самое, за исключением очистки буфера, как описано в других ответах. В любом случае, это избыточно, когда вы можете объединить два строковых литерала в один.
iBug

Что ж, если строка, которая должна быть напечатана, не является литералом, то вызовы <<будут равны 2 и в случае a , поэтому я бы не стал утверждать, что один или два <<(или два вызова функции в целом) будут Разница между \nи endl.
Энрико Мария Де Анжелис

Нет, я не пользуюсь \ n.
Карло Вуд

28

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

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

ISO / IEC 9899: 201x

7.21.3 §7

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

7.21.3 §3

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

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

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


19

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



10

Если вы используете 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 по умолчанию) - плохая идея.


31
Urgh! Кто бы хотел быть using namespace std;?? :-)
Стив Фолли

2
Насти. Спасибо за комментарий, я уверен, что другие столкнутся с этим.
Глава Geek

@ SteveFolly я делаю. Почему бы нет?
ʇolɐǝz ǝɥʇ qoq

@ ʇolɐǝzǝɥʇqoq Это нормально, если вы не делаете этого в заголовочных файлах.
Смерлин

1
@ ʇolɐǝzǝɥʇqoq Пожалуйста, избегайте using namespace std;. Это считается плохой практикой. Посмотрите, почему «используется пространство имен std;» считается плохой практикой?
LF

2

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


2

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

std::cout << "Test line" << std::endl; // with flush
std::cout << "Test line\n"; // no flush

1

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


Это из-за промывки? Я вижу, как это возможно.
Глава Geek

@ Действительно Голова. Я также видел, как это сказалось на производительности дискового ввода-вывода.
19

0

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.