доступной для ваших друзей? Для ваших приятелей студентов или сотрудников? Для каждого пользователя на вашей системе?
Глава 12 Общие библиотечные интерфейсы — часть 2
В главе 6, «Общие библиотечные интерфейсы — часть 1», был представлен первый набор API библиотеки общего пользования. В некотором смысле, эти API поддерживают работу с фундаментальными объектами, которыми управляют системы Linux и Unix: время дня, пользователи и группы для файлов, сортировка и поиск.
Данная глава более эклектична; функции API, рассмотренные здесь, не особо связаны друг с другом. Однако, все они полезны в повседневном программировании под Linux/Unix. Наше представление движется от простых,
более общих функций API к более сложным и более специализированным.
12.1. Операторы проверки:
assert
Оператор проверки (assertion) является утверждением, которое вы делаете о состоянии своей программы в определенный момент времени ее исполнения. Использование операторов проверок для программирования было первоначально разработано Хоаром (C.A.R. Hoare) [121] . Общая идея является частью «верификации программы»: так же, как вы проектируете и разрабатываете программу, вы можете показать, что она правильна, делая тщательно аргументированные утверждения о проявлениях кода вашей программы. Часто такие утверждения делаются об инвариантах — фактах о состоянии программы, которые, как предполагается, остаются верными на протяжении исполнения куска программы.
121
Однако, в своей лекции в честь присуждения премии Тьюринга Ассоциации по вычислительной технике в 1981 г. д-р Хоар утверждает, что эту идею выдвинул сам Алан Тьюринг — Примеч. автора.
Операторы проверки особенно полезны для описания двух разновидностей инвариантов: предусловий и постусловий: условий, которые должны быть истинными соответственно перед и после исполнения сегмента кода. Простым примером предусловий и постусловий является линейный поиск:
/* lsearch --- возвратить индекс с данным значением в массиве или -1,
если не найдено */
int lsearch(int *array, size_t size, int value) {
size_t i;
/* предусловие: array != NULL */
/* предусловие: size > 0 */
for (i = 0; i < size; i++)
if (array[i] == value)
return i;
/* постусловие: i == size */
return -1;
}
Этот пример определяет условия, используя комментарии. Но не было бы лучше проверить условия с использованием кода? Это является задачей макроса
assert
:
#include <assert.h> /* ISO С */
void assert(/* скалярное выражение */);
Когда скалярное выражение ложно, макрос
assert
выводит диагностическое сообщение и завершает программу (с помощью функции
варьирует от системы к системе. Для GLIBC на GNU/Linux сообщение включает имя программы, имя файла с исходным кодом и номер строки, имя функции, а затем текст завершившегося неудачей условия. (В этом случае именованная константа
NULL
проявляется в виде своего макрорасширения '
((void*)0)'
.)
Сообщение '
Aborted (core dumped)
' означает, что
ch12-assert
создала файл
core
; т.е. снимок адресного пространства процесса непосредственно перед его завершением. [122] Этот файл может быть использован впоследствии с отладчиком; см. раздел 15.3 «Основы GDB». Создание файла
core
является намеренным побочным результатом
assert
; предполагается, что произошла решительная ошибка, и вы хотите исследовать процесс с помощью отладчика для ее определения.
122
Как упоминалось в разделе 10.2 «Действия сигналов», некоторые дистрибутивы GNU/Linux запрещают создание файлов
core
. Чтобы снова разрешить их, поместите в свой файл
~/.profile
строку '
ulimit -S -с unlimited
' — Примеч. автора.
Вы можете отменить оператор проверки, компилируя свою программу с помощью опции командной строки '
– DNDEBUG
'. Когда этот макрос определен до включения
<assert.h>
, макрос
assert
расширяется в код, который ничего не делает. Например: