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

В связи с тем что макрос 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. Ошибки системных вызовов

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

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

Сбои системных вызовов происходят в самых разных ситуациях.

■ В системе могут закончиться ресурсы (или же программа может исчерпать лимит ресурсов, наложенный на нее системой). Например, программа может запросить слишком много памяти, записать чересчур большой объем данных на диск или открыть чрезмерное количество файлов одновременно.

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

■ Аргументы системного вызова могут оказаться неправильными либо по причине ошибочно введенных пользователем данных, либо из-за ошибки самой программы. Например, программа может передать системному вызову неправильный адрес памяти или неверный дескриптор файла. Другой вариант ошибки — попытка открыть каталог вместо обычного файла или передать имя файла системному вызову, ожидающему имя каталога.

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

Перейти на страницу:

Похожие книги

1С: Управление торговлей 8.2
1С: Управление торговлей 8.2

Современные торговые предприятия предлагают своим клиентам широчайший ассортимент товаров, который исчисляется тысячами и десятками тысяч наименований. Причем многие позиции могут реализовываться на разных условиях: предоплата, отсрочка платежи, скидка, наценка, объем партии, и т.д. Клиенты зачастую делятся на категории – VIP-клиент, обычный клиент, постоянный клиент, мелкооптовый клиент, и т.д. Товарные позиции могут комплектоваться и разукомплектовываться, многие товары подлежат обязательной сертификации и гигиеническим исследованиям, некондиционные позиции необходимо списывать, на складах периодически должна проводиться инвентаризация, каждая компания должна иметь свою маркетинговую политику и т.д., вообщем – современное торговое предприятие представляет живой организм, находящийся в постоянном движении.Очевидно, что вся эта кипучая деятельность требует автоматизации. Для решения этой задачи существуют специальные программные средства, и в этой книге мы познакомим вам с самым популярным продуктом, предназначенным для автоматизации деятельности торгового предприятия – «1С Управление торговлей», которое реализовано на новейшей технологической платформе версии 1С 8.2.

Алексей Анатольевич Гладкий

Финансы / Программирование, программы, базы данных
Встраиваемые системы. Проектирование приложений на микроконтроллерах семейства 68HC12/HCS12 с применением языка С
Встраиваемые системы. Проектирование приложений на микроконтроллерах семейства 68HC12/HCS12 с применением языка С

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

Дэниэл Дж. Пак , Стивен Ф. Барретт

Программирование, программы, базы данных / Компьютерное «железо» / Программирование / Книги по IT