std cerr что это
Урок №108. Обработка ошибок, cerr и exit()
Обновл. 13 Сен 2021 |
При написании программ возникновение ошибок почти неизбежно. Ошибки в языке C++ делятся на две категории: синтаксические и семантические.
Синтаксические ошибки
Синтаксическая ошибка возникает при нарушении правил грамматики языка C++. Например:
если 7 не равно 8, то пишем «not equal»;
Хотя этот стейтмент нам (людям) понятен, компьютер не сможет его корректно обработать. В соответствии с правилами грамматики языка C++, корректно будет:
Синтаксические ошибки почти всегда улавливаются компилятором и их обычно легко исправить. Следовательно, о них слишком беспокоиться не стоит.
Семантические ошибки
Семантическая (или «смысловая») ошибка возникает, когда код синтаксически правильный, но выполняет не то, что нужно программисту. Например:
Семантические ошибки не улавливаются компилятором и могут иметь разное влияние: некоторые могут вообще не отображаться, что приведет к неверным результатам, к повреждению данных или вообще к сбою программы. Поэтому о семантических ошибках беспокоиться уже придется.
Они могут возникать несколькими способами. Одной из наиболее распространенных семантических ошибок является логическая ошибка. Логическая ошибка возникает, когда программист неправильно программирует логику выполнения кода. Например, вышеприведенный фрагмент кода имеет логическую ошибку. Вот еще один пример:
Другой распространенной семантической ошибкой является ложное предположение. Ложное предположение возникает, когда программист предполагает, что что-то будет истинным или ложным, а оказывается наоборот. Например:
Безопасное программирование — это методика разработки программ, которая включает анализ областей, где могут быть допущены ложные предположения, и написание кода, который обнаруживает и обрабатывает любой случай такого нарушения, чтобы свести к минимуму риск возникновения сбоя или повреждения программы.
Определение ложных предположений
Оказывается, мы можем найти почти все предположения, которые необходимо проверить в одном из следующих трех мест:
При вызове функции, когда caller может передать некорректные или семантически бессмысленные аргументы.
При возврате значения функцией, когда возвращаемое значение может быть индикатором выполнения (произошла ли ошибка или нет).
При обработке данных ввода (либо от пользователя, либо из файла), когда эти данные могут быть не того типа, что нужно.
Поэтому, придерживаясь безопасного программирования, нужно следовать следующим 3-м правилам:
В верхней части каждой функции убедитесь, что все параметры имеют соответствующие значения.
После возврата функцией значения, проверьте возвращаемое значение (если оно есть) и любые другие механизмы сообщения об ошибках на предмет того, произошла ли ошибка.
Проверяйте данные ввода на соответствие ожидаемому типу данных и его диапазону.
Рассмотрим примеры проблем:
Проблема №1: При вызове функции caller может передать некорректные или семантически бессмысленные аргументы:
std:: cerr, std:: wcerr
Compiler support | ||||
Freestanding and hosted | ||||
Language | ||||
Standard library headers | ||||
Named requirements | ||||
Feature test macros (C++20) | ||||
Language support library | ||||
Concepts library (C++20) | ||||
Diagnostics library | ||||
General utilities library | ||||
Strings library | ||||
Containers library | ||||
Iterators library | ||||
Ranges library (C++20) | ||||
Algorithms library | ||||
Numerics library | ||||
Localizations library | ||||
Input/output library | ||||
Filesystem library (C++17) | ||||
Regular expressions library (C++11) | ||||
Atomic operations library (C++11) | ||||
Thread support library (C++11) | ||||
Technical specifications | ||||
Symbols index | ||||
External libraries |
These objects are guaranteed to be initialized during or before the first time an object of type std::ios_base::Init is constructed and are available for use in the constructors and destructors of static objects with ordered initialization (as long as is included before the object is defined).
Unless std :: ios_base :: sync_with_stdio ( false ) has been issued, it is safe to concurrently access these objects from multiple threads for both formatted and unformatted output.
[edit] Notes
The ‘c’ in the name refers to «character» (stroustrup.com FAQ); cerr means «character error (stream)» and wcerr means «wide character error (stream)».
[edit] Example
Поточный ввод-вывод в 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).
Результат выполнения
Обзор средств ввода-вывода в C++
Приложение, написанное на любом языке программирования, должно взаимодействовать с окружающим миром. Иначе пользы от него не будет. Как правило, такое взаимодействие осуществляется посредством ввода-вывода информации на монитор или в файл. Правда, есть некоторое множество программ, которые не используют файловый или консольный ввод-вывод: это программы, осуществляющие низкоуровневое взаимодействие с аппаратной частью компьютера и периферией (ядро ОС, драйверы и пр.), но это уже экзотика.
В стандартном C++ существует два основных пути ввода-вывода информации: с помощью потоков, реализованных в STL (Standard Template Library) и посредством традиционной системы ввода-вывода, унаследованной от C. Если копнуть немного глубже, то окажется, что и потоки, и традиционная система ввода-вывода для осуществления необходимых действий используют вызовы операционной системы. И это правильно.
Дальнейшее изложение не претендует на полноту, но описывает основные принципы использования библиотек. Подробности использования можно посмотреть в многочисленной литературе по C++ и STL, в MSDN и пр.
Традиционный ввод-вывод
Библиотека stdio предоставляет необходимый набор функций для ввода и вывода информации как в текстовом, так и в двоичном представлении. Следует отметить, что в отличие от классической C‑библиотеки, в современных библиотеках имеются более безопасные аналоги «классических» функций. Как правило, они имеют такое же имя, к которому добавлен суффикс _s. Рекомендуется использовать именно эти, безопасные функции.
Самая Первая Программа с использованием библиотеки stdio выглядит так:
В stdio для консольного ввода-вывода предусмотрена отдельная группа функций. Однако эти функции, как правило, являются обёртками для аналогичных функций файлового ввода-вывода, для которых аргумент типа FILE задан по умолчанию.
Самая Первая Программа с использование файлового вывода из библиотеки stdio выглядит так:
Некоторые популярные функции из stdio:
Сущность FILE представляет собой структуру, в которой хранится вся информация для управления потоком ввода-вывода.
Файл открывается функцией fopen(), которой передаются два параметра. Первый параметр определяет имя файла. Второй — определяет режим открытия файла: чтение, запись, произвольный доступ и т.п., а также указание на то, как работать с данными: в текстовом или двоичном режиме. Подробности — см. в документации.
Пример использования stdio
Ввод-вывод с помощью потоков STL
Самая Первая Программа с использованием потоков STL выглядит так:
Потоки cin, cout и cerr соответствуют потокам stdin, stdout и stderr соответственно.
Иерархия классов ввода-вывода STL достаточно сложна. Любители тонких ощущений могут найти её описание в литературе. Впрочем, остальных также не минует чаша сия, но только позже, когда потребуются знания чуть повыше того базового уровня, который описывается здесь.
Для ввода-вывода сначала необходимо создать поток — экземпляр соответствующего класса STL, а затем связать его с файлом. Для потока вывода используется класс ofstream, для потока ввода — ifstream, для потока ввода-вывода — fstream. В каждом из этих классов есть метод open(), который связывает поток с файлом. Проще говоря, открывает файл. Методу передаются два параметра: имя файла и режим открытия файла. Второй параметр представляет собой набор битовых флагов, определяющих режим открытия файла (чтение, запись и пр.) и способ работы с данными (текстовый или двоичный режим). Второй параметр опционален, т.е. имеет значение по умолчанию, соответствующее классу.
Вышеупомянутые классы имеют также конструкторы, позволяющие открыть файл сразу при создании потока. Параметры этих конструкторов полностью совпадают с параметрами метода open().
При ошибке открытия файла (в контексте логического выражения) поток получает значение false.
Файл закрывается методом close(). Этот метод также вызывается при разрушении экземпляров классов потоков.
Операции чтения и записи в поток, связанный с файлом, осуществляются либо с помощью операторов >, перегруженных для классов потоков ввода-вывода, либо с помощью любых других методов классов потоков ввода-вывода.
Некоторые наиболее употребляемые методы:
Пример использования потоков STL
Взаимодействие потокового и традиционного ввода-вывода
Апологеты C++ рекомендуют использовать для ввода-вывода только потоки STL и отказаться от использования традиционного ввода-вывода в духе C. Однако, ничто не мешает, по крайней мере пока, использовать традиционную систему ввода-вывода. Более того, предусмотрена специальная функция для синхронизации ввода-вывода, выполненного посредством потоков и посредством старых функций.
Заключение
Какой механизм использовать — вопрос предпочтений программиста, если работодателем явно не предписано использование конкретного механизма. В любом случае для физического ввода-вывода используются вызовы операционной системы. Всё остальное — обёртка, набор более или менее удобных функций или классов для взаимодействия с ОС.
Использование механизма потоков считается более безопасным. Но, как известно, плохую программу можно написать на любом языке программирования. Это также относится и к использованию библиотек. Автор статьи: Череп.
В чем разница между cout, cerr, засорением заголовка iostream в c ++? Когда использовать какой?
Решение
stdout а также stderr это разные потоки, хотя они оба ссылаются на вывод консоли по умолчанию. Перенаправление (трубопровод) одного из них (например, program.exe >out.txt ) не повлияет на других.
Другие решения
Как правило, вы используете std::cout для нормального выхода, std::cerr за ошибки и std::clog для «регистрации» (что может означать все, что вы хотите, чтобы это значило).
Основное отличие состоит в том, что std::cerr не буферизуется, как два других.
сегг не требует буфера, поэтому он быстрее других и не использует память, которая соиЬ использует, но потому что соиЬ буферизуется, в некоторых случаях это более полезно. Так:
Стандартный выходной поток (cout):
cout это пример ostream учебный класс. cout используется для вывода на стандартное устройство вывода, которым обычно является экран дисплея. Данные, которые необходимо отобразить на экране, вставляются в стандартный поток вывода ( cout ) используя оператор вставки ( ).
Небуферизованный стандартный поток ошибок (cerr): cerr стандартный поток ошибок, который используется для вывода ошибок. Это также пример ostream учебный класс. Как cerr является небуферизованный поэтому он используется, когда нам нужно немедленно отобразить сообщение об ошибке. У него нет буфера для хранения сообщения об ошибке и отображения позже.
Буферизированный стандартный поток ошибок (засорение): Это также пример ostream класс и используется для отображения ошибок, но в отличие cerr ошибка сначала вставляется в буфер и сохраняется в буфере, пока не будет заполнен полностью.
Разница этих 3 потоков в буферизации.
Пожалуйста, проверьте следующий код и запустите DEBUG через 3 строки: f (std :: clog), f (std :: cerr), f (std :: out), затем откройте 3 выходных файла, чтобы увидеть, что произошло. Вы можете поменять эти 3 строки, чтобы увидеть, что произойдет.
Из черновика стандартного документа C ++ 17:
30.4.3 Объекты с узким потоком [thin.stream.objects]
1 Объект cin управляет вводом из буфера потока, связанного с объектом stdin заявлено в (30.11.1).
3 Объект cout управляет выводом в буфер потока, связанный с объектом stdout заявлено в (30.11.1).
4 Объект cerr управляет выводом в буфер потока, связанный с объектом stderr заявлено в (30.11.1).
6 Объект clog управляет выводом в буфер потока, связанный с объектом stderr заявлено в (30.11.1).
Обсуждение …
cout пишет stdout ; cerr а также clog в stderr
Стандартный выход ( stdout ) предназначен для получения не ошибочных, не диагностических выходных данных из программы, таких как выходные данные успешной обработки, которые могут быть отображены конечному пользователю или переданы на некоторый дополнительный этап обработки.
Стандартная ошибка ( stderr ) предназначен для диагностических выводов, таких как предупреждения и сообщения об ошибках, которые указывают, что программа не произвела или не выдала вывод, который мог ожидать пользователь. Этот ввод может отображаться конечному пользователю, даже если выходные данные передаются на дальнейшую стадию обработки.
cin а также cerr привязаны к cout
Это контрастирует с clog — если вы напишите там, он не будет буферизован и ни к чему не привязан, поэтому он будет буферизовать приличное количество журналов перед сбросом. Это дает наивысшую пропускную способность сообщений, но означает, что сообщения могут быть не быстро видны потенциальному потребителю, читающему терминал или следящему за журналом.
И то и другое соиЬ а также загромождать буферизованы но сегг небуферизован, и все это предопределенные объекты, которые являются экземплярами класса ostream.
Основное использование этих трех соиЬ используется для стандартного ввода, тогда как загромождать а также сегг используется для отображения ошибок.
Суть почему сегг небуферизован, может быть потому, что у вас есть несколько выходов в буфере, и в коде упоминается исключение ошибки, тогда вам нужно немедленно отобразить эту ошибку, что может быть сделано сегг эффективно.
Пожалуйста, поправьте меня, если я ошибаюсь.