#include
int comp(const void * p1, const void * p2) /* обязательная форма */
{
/* получение правильного типа указателя */ const struct names *psl = (const struct names *) p1; const struct names *ps2 = (const struct names *) p2; int res;
res = strcmp(psl->last, ps2->last); /* сравнение фамилий */
if (res |= 0) return res;
else /* фамилии одинаковы, поэтому сравнить имена */
return strcmp(psl->first, ps2->first);
)
В данной функции сравнение осуществляется с помощью функции strcmp(), которая возвращает значения, удовлетворяющие требованиям к функции сравнения. Обратите внимание, что для применения операции -> необходим указатель на структуру.
Библиотека утверждений
Библиотека утверждений, поддерживаемая заголовочным файлом assert.h — это небольшая библиотека, предназначенная для оказания содействия при отладке программы. Она состоит из макроса по имени assert(). Макрос принимает в качестве аргумента целочисленное выражение. Если выражение оценивается как ложное (ненулевое), макрос assert() выводит в стандартный поток ошибок (stderr) сообщение об ошибке и вызывает функцию abort(), которая прекращает выполнение программы. (Прототип функции abort() находится в заголовочном файле stdlib.h.) Идея состоит в том, чтобы идентифицировать критические места в программе, где должны быть истинными определенные условия, и с помощью оператора assert() завершать программу, если одно из указанных условий нарушается. Обычно аргументом служит выражение отношения или логическое выражение. Когда assert() прекращает выполнение программы, сначала отображается не прошедший проверку тест, имя файла, содержащего этот тест, и номер строки, где находится тест.
Использование assert()
В листинге 16.18 приведен простой пример применения assert(). В нем утверждается, что значение z должно быть больше или равно 0, прежде чем будет предпринята попытка извлечь из него квадратный корень. Кроме того, ошибочно выполняется вычитание значения вместо его сложения, делая возможным получение переменной z недопустимого значения.
Препроцессор и библиотека С 705
Листинг 16.18. Программа assert.с

Ниже показаны результаты пробного запуска:
Введите пару чисел (0 0 для завершения) :
4 3
результатом является 2.645751
Введите следующую пару чисел:
5 3
результатом является 4.000000
Введите следующую пару чисел:
3 5
Assertion failed: (z >= 0), function main, file /Users/assert.c, line 14.
Отказ утверждения: (z >= 0), функция main, файл /Users/assert. с, строка 14.
Точный текст в последней строке зависит от компилятора. Потенциально может сбивать с толку то, что в сообщении не говорится об условии z >= 0; вместо этого в нем уведомляется о том, что отказало утверждение z >= 0.
Чего-то похожего можно было бы добиться с помощью оператора if:
if (z < 0)
{
puts("z меньше 0"); abort();
}
Тем не менее, подход с assert() обладает рядом преимуществ. Он автоматически идентифицирует файл и номер строки, где возникла проблема. Наконец, существует механизм включения и отключения макроса assert() без необходимости в изменении кода. Если вы считаете, что устранили ошибки в программе, поместите следующее определение макроса
#define NDEBUG
перед местом включения файла assert .h, повторно скомпилируйте программу, и компилятор отключит в файле все операторы assert(). Если проблема возникнет снова, можете удалить директиву #define (или закомментировать ее) и провести повторную компиляцию, в результате чего все операторы assert() снова активизируются.
706 глава 16
_Static_assert (С11)
Выражение assert() проверяется во время выполнения. В С11 появилось новое средство в форме объявления _Static_assert, которое осуществляет проверку на этапе компиляции. Таким образом, assert() может привести к прерыванию выполняющейся программы, тогда как _Static_assert() может стать причиной того, что программа не компилируется. Объявление _Static_assert принимает два аргумента. Первым из них является целочисленное константное выражение, а вторым — строка. Если выражение оценивается в 0 (или _False), то компилятор отобразит строку, и не будет компилировать программу. Давайте рассмотрим короткий пример в листинге 16.19, после чего взглянем на отличия между assert() и _Static_assert().
Листинг 16.19. Программа statasrt.c

Ниже показана попытка проведения компиляции в командной строке:
$ clang statasrt.c
statasrt.с:4:1: error: static_assert failed "Ошибочно предполагается 16битовый тип char"
Читать дальше