Чтение онлайн

на главную - закладки

Жанры

Программирование для Linux. Профессиональный подход

Самьюэл Алекс

Шрифт:

В Linux есть ряд других функций, предназначенных для генерирования временных файлов или их имен, в частности

mktemp
,
tmpnam
и
tempnam
. Работать с ними нежелательно, поскольку возникают упоминавшиеся выше проблемы, связанные с надежностью и безопасностью.

2.2. Защита от ошибок

Написать программу, которая корректно работает при "разумном" использовании, — трудная задача. Написать программу, которая ведет себя "разумно" при возникновении ошибок, — еще труднее. В этом разделе описываются методики программирования,

позволяющие выявлять ошибки на ранних стадиях и решать проблемы, возникающие в ходе выполнения программы.

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

2.2.1. Макрос assert

При написании программы следует помнить о том, что ошибки и непредвиденные ситуации могут радикально менять работу программы на самых ранних стадиях ее выполнения. Нужно стараться выявлять такие ошибки как можно раньше, на этапах разработки и отладки. Остальные ошибки, влияние которых на работу программы незначительно, обычно остаются незамеченными до тех пор, пока пользователи не начнут запускать программу.

Простейший способ выявления ненормальных ситуаций — стандартный макрос

assert
в языке С. Его аргументом является булево выражение. Программа завершается, если выражение оказывается ложным, при этом выводится сообщение об ошибке с указанием исходного файла и номера строки, а также текста выражения, приведшего к ошибке. Макрос
assert
оказывается очень полезным для самых разных проверок целостности, выполняемых внутри программы. Например, с помощью этого макроса проверяют правильность аргументов функций, выполнение входных и выходных условий при вызове функций (а также методов C++) и наличие непредвиденных возвращаемых значений.

Каждый вызов макроса

assert
является не только проверкой, осуществляемой на этапе выполнения, но и документацией, описывающей работу программы непосредственно в ее исходном тексте. Когда программа содержит строку assert (условие), то любой, кто читает исходный текст, будет знать, что в данной точке программы указанное условие всегда должно быть истинным. Если же условие не выполняется, то, очевидно, в программе присутствует ошибка.

В программах, критических к требованиям производительности, проверки

assert
на этапе выполнения могут представлять собой слишком большую нагрузку. В таких случаях программа компилируется с установленной макроконстантой
NDEBUG
; для этого в командной строке компилятора указывается флаг
– DNDEBUG
. При наличии данной макроконстанты препроцессор убирает из тела программы все вызовы макроса
assert
. И все же помните: делать это имеет смысл только тогда, когда производительность является узким местом программы, причем макрос нужно отключать лишь в наиболее критических файлах.

В связи с тем что макрос

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

Предположим, к примеру,

что в цикле вызывается функция
do_something
. В случае успешного выполнения она возвращает 0, иначе — ненулевое значение. Легкомысленный программист считает, что функция всегда завершается успешно, поэтому возникает соблазн написать так:

for (i =0; i < 100; ++i)

 assert(do_something == 0);

Позднее, забыв о данной особенности, программист решает, что проверки на этапе выполнения заметно снижают производительность программы и нужно перекомпилировать программу с включенной макроконстантой

NDEBUG
. В результате из программы будут удалены все макросы
assert
, и функция
do_something
вообще не будет вызвана. На самом деле необходимо использовать следующий подход:

for (i = 0; i < 100; ++i) {

 int status = do_something;

 assert(status == 0);

}

Еще один важный момент: макрос

assert
не следует применять для проверки данных, вводимых пользователем. Пользователи не любят, когда программа аварийно завершает свою работу, выдавая малопонятное сообщение об ошибке, даже если причиной этого стали неправильно введенные данные. Конечно, входные данные всегда нужно проверять, но другими способами. Макрос
assert
предназначен лишь для внутренних проверок.

Дадим несколько полезных советов.

■ Проверяйте наличие пустых указателей, например в списке аргументов функции. Сообщение об ошибке, генерируемое строкой

{assert (pointer != NULL)}
,

Assertion 'pointer != ((void *)0)' failed.

более информативно, чем сообщение, выдаваемое в ответ на попытку раскрытия пустого указателя:

Segmentation fault (core dumped)

■ Проверяйте значения параметров функции. Например, если в функции предполагается, что параметр

foo
имеет только положительные значения, поставьте следующую проверку в самом начале тела функции:

assert(foo > 0);

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

2.2.2. Ошибки системных вызовов

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

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

Поделиться:
Популярные книги

Мастер...

Чащин Валерий
1. Мастер
Фантастика:
героическая фантастика
попаданцы
аниме
6.50
рейтинг книги
Мастер...

Жених из гроба

Сотис Майя
1. Гробокопательница
Фантастика:
юмористическое фэнтези
сказочная фантастика
фэнтези
5.00
рейтинг книги
Жених из гроба

Ищу жену с прицепом

Рам Янка
2. Спасатели
Любовные романы:
современные любовные романы
6.25
рейтинг книги
Ищу жену с прицепом

Гримуар тёмного лорда I

Грехов Тимофей
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Гримуар тёмного лорда I

Заклятие предков

Прозоров Александр Дмитриевич
3. Ведун
Фантастика:
фэнтези
альтернативная история
8.49
рейтинг книги
Заклятие предков

Крепость над бездной

Лисина Александра
4. Гибрид
Фантастика:
боевая фантастика
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Крепость над бездной

Рота Его Величества

Дроздов Анатолий Федорович
Новые герои
Фантастика:
боевая фантастика
8.55
рейтинг книги
Рота Его Величества

Экспансия: Сотрудничество. Том 5

Белов Артем
5. Планетарный десант
Фантастика:
боевая фантастика
аниме
5.00
рейтинг книги
Экспансия: Сотрудничество. Том 5

Отверженный III: Вызов

Опсокополос Алексис
3. Отверженный
Фантастика:
фэнтези
альтернативная история
7.73
рейтинг книги
Отверженный III: Вызов

Князь Серединного мира

Земляной Андрей Борисович
4. Страж
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Князь Серединного мира

Возвышение Меркурия. Книга 8

Кронос Александр
8. Меркурий
Фантастика:
героическая фантастика
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 8

Эволюционер из трущоб. Том 5

Панарин Антон
5. Эволюционер из трущоб
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Эволюционер из трущоб. Том 5

Локки 7. Потомок бога

Решетов Евгений Валерьевич
7. Локки
Фантастика:
аниме
эпическая фантастика
фэнтези
5.00
рейтинг книги
Локки 7. Потомок бога

Черный Маг Императора 4

Герда Александр
4. Черный маг императора
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Черный Маг Императора 4