std endl c что это
1.5 – Знакомство с iostream: cout, cin и endl
Библиотека ввода/вывода
Библиотека ввода/вывода (библиотека io) является частью стандартной библиотеки C++, которая имеет дело с базовым вводом и выводом. Мы будем использовать функции этой библиотеки для получения ввода с клавиатуры и вывода данных в консоль. Буквы io в iostream означают «input/output» (ввод/вывод).
std::cout
Вспомним нашу программу Hello world :
std::cout может печатать не только текст, но и числа:
Это дает результат:
Его также можно использовать для вывода значений переменных:
Это дает результат:
Чтобы напечатать несколько элементов в одной строке, для объединения (связывания) нескольких частей выводимых данных, оператор вставки ( ) можно использовать несколько раз в одном выражении. Например:
Эта программа печатает:
Вот еще один пример, в котором мы печатаем и текст, и значение переменной в одном выражении:
Эта программа печатает:
std::endl
Как вы думаете, что напечатает следующая программа?
Результат может вас удивить:
Отдельные выражения вывода не приводят к отдельным выводимым строкам в консоли.
Если мы хотим выводить в консоль отдельные выводимые строки, нам нужно указать консоли, когда необходимо переместить курсор на следующую строку.
Совет
В приведенной выше программе второй std::endl технически не нужен, так как программа сразу же после этого завершается. Однако он служит двум полезным целям: во-первых, он помогает указать, что строка вывода является «законченной мыслью». Во-вторых, если мы позже захотим добавить дополнительные выражения вывода, нам не нужно будет изменять существующий код. Мы можем просто добавить новые выражения.
std::endl против ‘\n’
Вот пример, в котором ‘\n’ используется двумя разными способами:
Этот код напечатает:
Обратите внимание, что когда ‘\n’ используется сам по себе для перемещения курсора на следующую строку, необходимы одинарные кавычки. При встраивании в текст, который уже заключен в двойные кавычки, одинарные кавычки не нужны.
Мы рассмотрим, что такое ‘\n’ более подробно, когда перейдем к уроку о символах (4.11 – Символы).
Лучшая практика
Предупреждение
‘\n’ использует обратный слеш (как и все специальные символы в C++), а не прямой слеш. Использование прямого слеша (например, ‘/n’ ) может привести к неожиданному поведению.
std::cin
Если ваш экран закрывается сразу после ввода числа, обратитесь к уроку «0.8 – Несколько основных проблем C++» для решения этой проблем.
Лучшая практика
Существуют споры о том, нужно ли инициализировать переменную непосредственно перед тем, как передать ей значение, предоставленное пользователем, через другой источник (например, std::cin ), поскольку значение, предоставленное пользователем, просто перезапишет значение инициализации. В соответствии с нашей предыдущей рекомендацией о том, что переменные всегда следует инициализировать, лучше всего сначала инициализировать переменную.
Мы обсудим, как std::cin обрабатывает недопустимые входные данные в следующем уроке (7.16 – std::cin и обработка недопустимых входных данных).
Для продвинутых читателей
Резюме
Подробнее об операторах мы поговорим в уроке «1.9 – Знакомство с литералами и операторами».
Небольшой тест
Вопрос 1
Рассмотрим следующую программу, которую мы использовали выше:
Запустите эту программу несколько раз и опишите, что произойдет, если вместо этого вы введете следующие типы входных данных:
б) Число с дробной частью. Попробуйте числа с дробными составляющими меньше 0,5 и больше 0,5 (например, 3,2 и 3,7).
Дробная составляющая опущена.
Всё прекрасно работает.
г) Слово, например «Hello».
д) Действительно большое число (минимум 3 миллиарда).
Вы получаете, казалось бы, случайное число.
Последнее предложение может быть особенно неожиданным. Попробуйте! Это происходит потому, что x может содержать числа только до определенного размера. После этого он «переполняется». Мы обсудим переполнение в следующем уроке.
setprecision() выглядит как вызов функции, но при использовании экземпляра cout ничего не печатается. Это меняет точность, но почему бы просто не использовать соответствующий член функции вместо добавления «абстракции» к написанию кода? Под абстракцией я подразумеваю неинтуитивный код.
2 ответа
Что на самом деле является endl? Конечно, он печатает новую строку и очищает буфер ostream. Но что это на самом деле?
Вставляет символ новой строки в выходную последовательность os и очищает его
Могут ли программисты определять такие «сущности», как endl?
Вот демонстрационная программа.
std::basic_ostream::operator имеет перегрузку, которая принимает указатель на такой функция:
Реализация std::endl может затем записать в заданный std::ostream и очистить его, например:
Итак, когда у вас есть такое утверждение:
Это на самом деле будет называть это внутренне:
Который тогда назовет:
Могут ли программисты определять такие «сущности», как endl?
что на самом деле происходит при выполнении такой команды, как: cout
setprecision() выглядит как вызов функции
Это IS вызов функции. Манипуляторы ввода / вывода, которые принимают пользовательский ввод, работают немного иначе, чем манипуляторы ввода / вывода, которые не принимают никакого пользовательского ввода.
Таким образом, утверждение, подобное этому:
На самом деле будет называть что-то вроде этого:
Который затем будет внутренне звонить:
пока ничего не печатается при использовании экземпляра cout. Это меняет точность
Однако ничто не мешает манипулятору ввода-вывода записывать данные в std::ostream (или читать из std::istream ), если он этого хочет.
почему бы просто не использовать соответствующий член функции вместо добавления «абстракции» к написанию кода?
Который в конечном счете назовет что-то подобное внутри:
Не так ли просто, как просто с использованием перегрузок?
Почему мы должны избегать использования std :: endl
Обычной практикой является использование std :: endl для печати новых строк при использовании cout. Для небольших программ с очень небольшим количеством операций ввода-вывода такая практика является приемлемой, но если большая часть операций ввода-вывода увеличивается, то эффективность программы снижается.
std :: endl не только добавляет новые строки в поток, но также очищает буфер каждый раз, когда он используется. Таким образом, когда мы пишем
Мы на самом деле делаем что-то вроде этого
Очистка буферов является задачей операционной системы. Каждый раз, когда буфер очищается, к ОС должен быть сделан запрос, и эти запросы сравнительно дороги. Более того, нам не нужно очищать буфер каждый раз, когда мы записываем что-то в поток, так как буферы очищаются автоматически при заполнении. В редких случаях, когда нам нужно выполнить сброс, мы можем явно указать операцию, используя либо cout.flush (), либо вставив std :: flush в поток.
Запись символов ‘/ n’ непосредственно в поток более эффективна, поскольку не вызывает сброса, как std :: endl.
Демонстрация влияния на производительность
Следующая программа на C ++ демонстрирует влияние std :: endl на производительность. Мы записываем 100000 строк в два файла один раз, используя std :: endl, а затем снова используя / n. В каждом случае мы измеряем время выполнения и печатаем это время
#include
#include
#include
using namespace std;
using namespace std::chrono;
ofstream file1( «file1.txt» );
ofstream file2( «file2.txt» );
// Пишем в file1 используя endl
// Для измерения времени выполнения в C ++
// ссылаемся на эту статью
auto start = high_resolution_clock::now();
auto stop = high_resolution_clock::now();
auto duration = duration_cast (stop-start);
cout «Writing to file using endl took «
// Записать в file2 используя / n
file2 «Hello World \n» ;
duration = duration_cast (stop-start);
cout «Writing to file using \\n took «
Выход: (зависит от машины)
Как видно из вывода std :: endl заняло почти вдвое больше времени. В некоторых системах влияние на производительность может быть еще хуже. Обратите внимание, что гарантировано, что std :: endl займет больше времени, чем вывод ‘/ n’ непосредственно в поток.
Поточный ввод-вывод в C++
Поточный ввод-вывод в C++ выполняется с помощью функций сторонних библиотек. В С++, как и в С, нет встроенных в язык средств ввода-вывода.
Библиотека iostream определяет три стандартных потока:
Для их использования в Microsoft Visual Studio необходимо прописать строку:
Для выполнения операций ввода-вывода переопределены две операции поразрядного сдвига:
Возможно многократное назначение потоков:
cout
Ввод информации
При этом из входного потока читается последовательность символов до пробела, затем эта последовательность преобразуется к типу идентификатора, и получаемое значение помещается в идентификатор:
Возможно многократное назначение потоков:
cin >> переменная1 >> переменная2 >>. >> переменнаяn;
При наборе данных на клавиатуре значения для такого оператора должны быть разделены символами (пробел, \n, \t ).
Особого внимания заслуживает ввод символьных строк. По умолчанию потоковый ввод cin вводит строку до пробела, символа табуляции или перевода строки.
Результат выполнения
Для ввода текста до символа перевода строки используется манипулятор потока getline() :
Результат выполнения
Манипуляторы потока
В С++ имеется ряд манипуляторов. Рассмотрим основные:
Манипулятор | Описание |
endl | Помещение в выходной поток символа конца строки ‘\n’ |
dec | Установка основания 10-ой системы счисления |
oct | Установка основания 8-ой системы счисления |
hex | Установка основания 16-ой системы счисления |
setbase | Вывод базовой системы счисления |
width(ширина) | Устанавливает ширину поля вывода |
fill(‘символ’) | Заполняет пустые знакоместа значением символа |
precision(точность) | Устанавливает количество значащих цифр в числе (или после запятой) в зависимости от использования fixed |
fixed | Показывает, что установленная точность относится к количеству знаков после запятой |
showpos | Показывает знак + для положительных чисел |
scientific | Выводит число в экспоненциальной форме |
get() | Ожидает ввода символа |
getline(указатель, количество) | Ожидает ввода строки символов. Максимальное количество символов ограничено полем количество |
Пример Программа ввода-вывода значения переменной в C++
Та же программа, написанная на языке Си
Пример Использование форматированного вывода
Результат выполнения
Еще один пример использования форматированного вывода: для t∈[0;3] с шагом 0,5 вычислить значение y=cos(t).
Результат выполнения
Должен ли всегда использоваться std :: endl?
Я прыгаю с C на C ++ с помощью книги C ++ Primer (5-е издание), где автор утверждает следующее:
Программисты часто добавляют операторы печати во время отладки. такие
заявления всегда должны сбрасывать поток. В противном случае, если программа
вылетает, вывод может быть оставлен в буфере, что приводит к неправильному
выводы о том, где программа потерпела крах.
Но сообщения онлайн предлагают иначе; некоторые говорят, что постоянная очистка буфера вредна для программы и вызывает проблемы с производительностью.
Решение
Начиная с пункта 4, потому что все остальное зависит от него, и с пункта 3, потому что он тесно связан.
Когда вы очищаете поток, вы берете все данные, хранящиеся в потоке, и записываете их на базовый носитель, представленный потоком.
Дело в том, что вы не хотите писать в IO очень часто, потому что все, что выходит из ЦП, занимает безбожное количество времени по сравнению с тем, что остается внутри ЦП. Иногда в десятки тысяч раз медленнее. Внутри процессора у вас есть гигагерц и параллельные шины, передающие данные 32 или более бит за раз. Снаружи у вас есть мегагерцы, часто движущиеся по одному.
Возьмите файл в качестве классического примера. Мало того, что доступ к диску работает с частотой процессора, но если каждый байт идет непосредственно на диск, то для каждого байта вам может потребоваться
Brutal. Представьте, что вы делаете это несколько сотен или несколько тысяч раз, чтобы написать одну строку. Но что, если вы написали строку только тогда, когда она стала слишком большой для хранения, или вы закончили? Что, если вы пишете в секторах, а не в байтах? Тогда вы могли бы
Одна операция для потенциально тысяч байт в одном кадре.
Пункт 2 восходит к пункту четыре / три, вы не можете прочитать то, что не смываете. Если вы хотите увидеть определенный вывод на экране, и вы хотите увидеть его сейчас, вы сбросите. Если вы хотите вывести отладочное сообщение до сбоя программы и, скорее всего, завершить работу, не выводя на экран последние несколько абсолютно важных сообщений, вы можете выполнить сброс. История переполнена программистами, которые искали не то место, чтобы найти ошибку, потому что они не получили эти последние несколько чистых сообщений об ошибках.
Вы торгуете скоростью программы для относительной уверенности в том, что вы увидите важное сообщение, когда вам нужно это увидеть.
Примите совет Пита Беккера и используйте std::cerr для ошибок и отладки, где это возможно. Вот для чего он был построен. Он действует на грубую силу и невежество. Это больно. Это медленно. И это почти всегда работает.
Другие решения
Отладочный вывод должен быть записан в std::cerr ; это единица буферизована, поэтому каждый персонаж сбрасывается. Редко возникает необходимость std::endl и его использование приведет к загадочно медленному коду. Просто используйте ‘\n’ если вы не знаете, что вам нужно очистить буфер.
И автор и посты правы.
1) Когда вы должны использовать std :: endl?
Когда вы хотите быть уверены, что буфер немедленно очищается.
2) Является ли автор ошибочным или я скучаю по какой-либо части того, что он
заявил?
Нет, автор правильный, и вы тоже.
3) Можете ли вы дать какие-либо реальные сценарии реальной необходимости промывки
выходной поток?
Когда конкретная строка записывается в поток много раз за короткое время std::endl действительно может вызвать потерю производительности из-за ненужной очистки буфера каждый раз. Однако, когда дело доходит до печати строк, которые добавляются с единственной целью отладки, вы всегда должны очищать буфер. Опять же, если вы отлаживаете приложение, просто печатая строки без использования отладчика, вы сначала делаете что-то не так.
полностью буферизованный, если и только если поток может быть определен как не относящийся к
на интерактивное устройство.
(C99, 7.19.3 Files, пункт 7.)
Это означает, что если ваш вывод отправляется на терминал, std::endl против «\n» не имеет значения в первую очередь. 😉
Относительно вашего актуального вопроса:
И то и другое верно
Это становится проблемой только после добавления «всегда».
Когда ты хочу очистить буфер.
Является ли автор ошибочным или я не понял какую-либо часть того, что он сказал?
Я думаю, что абсолютные квантификаторы, такие как «всегда», «все», «никогда» и т. Д., Должны приниматься с недоверием в том, что касается стиля / дизайна / и т. Д.
(Исключение: Никогда вызвать неопределенное поведение. ;-))
Можете ли вы дать какие-либо реальные сценарии реальной необходимости очистки выходного потока?
Всякий раз, когда не имея самый последний вывод на самом деле появится не будет приемлемым. Является ли это случаем в каком-либо конкретном сценарии, это вызов для суждения.
Лично я бы рассматривал журналы производства / транзакций как Больше критически, чем журналы отладки …