C++: "std::endl" против "\n"
Многие книги C++ содержат пример кода, подобного этому...
std::cout << "Test line" << std::endl;
... так что я всегда так делал. Но вместо этого я видел много кода от таких разработчиков:
std::cout << "Test line\n";
Есть ли техническая причина, чтобы отдавать предпочтение одному над другим, или это просто вопрос стиля кодирования?
15 ответов
Различные символы конца строки не имеют значения, при условии, что файл открыт в текстовом режиме, который вы получите, если не запросите двоичный файл. Скомпилированная программа выпишет правильную вещь для системы, для которой скомпилировано.
Единственная разница в том, что std::endl
очищает выходной буфер и '\n'
не делает. Если вы не хотите, чтобы буфер часто очищался, используйте '\n'
, Если вы это сделаете (например, если вы хотите получить все выходные данные, а программа работает нестабильно), используйте std::endl
,
Разницу можно проиллюстрировать следующим:
std::cout << std::endl;
эквивалентно
std::cout << '\n' << std::flush;
Так,
- использование
std::endl
Если вы хотите форсировать немедленный сброс на выходе. - использование
\n
если вы беспокоитесь о производительности (что, вероятно, не так, если вы используете<<
оператор).
я использую \n
на большинстве линий.
Тогда используйте std::endl
в конце абзаца (но это просто привычка и обычно не требуется).
Вопреки другим утверждениям, \n
символ отображается на правильную платформу конца строки, только если поток идет в файл (std::cin
а также std::cout
быть особенным, но все же файлом (или подобным файлу)).
Там могут быть проблемы с производительностью, std::endl
вызывает сброс потока вывода.
Там есть еще один вызов функции, если вы собираетесь использовать std::endl
a) std::cout << "Hello\n";
b) std::cout << "Hello" << std::endl;
а) звонит оператору <<
один раз.
б) звонит оператору <<
дважды.
Я вспомнил, прочитав об этом в стандарте, так что здесь идет:
См. Стандарт C11, который определяет, как ведут себя стандартные потоки, поскольку программы на C++ взаимодействуют с 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
если только конвейерная обработка файлов: C++ ref на std:: endl.
Они оба напишут соответствующий символ конца строки. В дополнение к этому endl приведет к тому, что буфер будет зафиксирован. Обычно вы не хотите использовать endl при выполнении файлового ввода-вывода, потому что ненужные коммиты могут повлиять на производительность.
Ничего страшного, но endl не будет работать в boost:: lambda.
(cout<<_1<<endl)(3); //error
(cout<<_1<<"\n")(3); //OK , prints 3
Если вы используете 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 для использования пространства имен, так что вы получите ошибку компиляции для примера выше.
РЕДАКТИРОВАТЬ: Забыл упомянуть, Qt's endl
объявлен в "qtextstream.h", который является частью QtCore
* EDIT2: C++ выберет правильный endl
если у тебя есть using
за std::cout
или пространство имен std
, поскольку std::endl
находится в том же пространстве имен, что и std::cout
Механизм ADL в C++ выберет std::endl
,
Я никогда не видел, чтобы кто-то говорил, что на это влияет форматирование cout:
#include <iostream>
#include <iomanip>
int main() {
std::cout << "\\n:\n" << std::setw(2) << std::setfill('0') << '\n';
std::cout << "std::endl:\n" << std::setw(2) << std::setfill('0') << std::endl;
}
Выход:
\n:
0
std::endl:
Обратите внимание: поскольку это один символ, а для заполнения установлено значение 2, перед печатью печатается только 1 ноль.
'\n'
.
Я нигде не могу найти ничего об этом, но он воспроизводится с помощью clang, gcc и msvc.
Я был очень смущен, когда впервые увидел это.
Со ссылкой Это манипулятор ввода-вывода только для вывода.
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', поощряемое некоторыми источниками, может значительно снизить производительность вывода.
endl
манипулятор эквивалентен '\'
, Но endl
всегда сбрасывает поток.
std::cout << "Test line" << std::endl; // with flush
std::cout << "Test line\n"; // no flush
У меня всегда была привычка просто использовать std::endl, потому что это легко увидеть.
Если вы намереваетесь запустить свою программу на другом ноутбуке, никогда не используйте endl
заявление. Особенно, если вы пишете много коротких строк или, как я часто видел, отдельные символы в файле. Использование endl
известно, чтобы убить сетевые файловые системы, такие как NFS.
Из документов GCC:
Некоторые люди также считают, что отправка endl в выходной поток приводит только к новой строке. Это неверно ; после записи новой строки буфер также очищается. Возможно, это тот эффект, который вам нужен при записи на экран — выведите текст как можно скорее и т. д. — но при этом в файле буферизация в значительной степени тратится впустую:
output << "a line of text" << endl;
output << some_data_variable << endl;
output << "another line of text" << endl;
В этом случае правильнее всего просто записать данные и позволить библиотекам и системе позаботиться о буферизации. Если вам нужна новая строка, просто напишите новую строку:
output << "a line of text\n"
<< some_data_variable << '\n'
<< "another line of text\n";
Вы можете проверить документацию ostream или проверитьendl
сама реализация - в моем случае usr/include/c++/11/ostream:684 -. Там вы найдете:
// Standard basic_ostream manipulators
/**
* @brief Write a newline and flush the stream.
*
* This manipulator is often mistakenly used when a simple newline is
* desired, leading to poor buffering performance. See
* https://gcc.gnu.org/onlinedocs/libstdc++/manual/streambufs.html#io.streambuf.buffering
* for more on this subject.
*/
template<typename _CharT, typename _Traits>
inline basic_ostream<_CharT, _Traits>&
endl(basic_ostream<_CharT, _Traits>& __os)
{ return flush(__os.put(__os.widen('\n'))); }
Если ты не заметил, endl
это как нажатие клавиши ВВОД в то время как "\n"
это как нажатие клавиши ВВОД + ПРОБЕЛ.