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

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

Жанры

Linux программирование в примерах

Роббинс Арнольд

Шрифт:

38

39 printf("index = %d\n", index);

40

41 return 0;

42 }

После компиляции и запуска оператор проверки в строке 12 «выстреливает»:

$ ch12-assert /* Запуск программы */

ch12-assert: ch12-assert.c:12: lsearch: Assertion 'array != ((void *)0)' failed.

Aborted (core dumped)

Сообщение от

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
расширяется в код, который ничего не делает. Например:

$ gcc -DNDEBUG=1 ch12-assert.c -о ch12-assert /* Компиляция с -DNDEBUG */

$ ch12-assert /* Запуск */

Segmentation fault (core dumped) /* Что случилось? */

Здесь мы получили настоящий дамп ядра! Мы знаем, что операторы проверки были запрещены; сообщения «failed assertion» нет. Что же случилось? Рассмотрите строку 15

lsearch
при вызове из строки 37
main
. В этом случае переменная
array
равна
NULL
. Доступ к памяти через указатель
NULL
является ошибкой. (Технически различные стандарты оставляют «неопределенным» то, что происходит при разыменовывании указателя
NULL
. Наиболее современные системы делают то же, что и GNU/Linux; они завершают процесс, посылая ему сигнал
SIGSEGV
; это, в свою очередь, создает дамп ядра. Этот процесс описан в главе 10 «Сигналы».

Этот случай поднимает важный момент относительно операторов проверки. Часто программисты ошибочно используют операторы проверки вместо проверки ошибок времени исполнения. В нашем случае тест '

array != NULL
' должен был быть проверкой времени исполнения:

if (array == NULL) return -1;

Тест '

size > 0
' (строка 13) менее проблематичен; если
size
равен 0 или меньше 0, цикл никогда не исполнится, и
lsearch
(правильно) возвратит -1. (По правде, этот оператор проверки не нужен, поскольку код правильно обрабатывает случай '
size <= 0
'.)

Логика, стоящая за отменой

оператора проверки, заключается в том, что дополнительные проверки могут снизить производительность программы и поэтому должны быть запрещены в заключительной версии программы. Хоар [123] , однако, сделал такое замечание:

«В конце концов, абсурдно делать тщательные проверки безопасности при отладочных запусках, когда к результатам нет никакого доверия, а затем удалять их из финальных версий, когда ошибочный результат может быть дорогим или катастрофическим. Что бы мы подумали об энтузиасте-мореплавателе, который надевает свой спасательный жилет при тренировке на сухой земле и снимает его, как только выходит в море?»

123

Hints On Programming Language Design, C.A.R. Hoare Stanford University Computer Science Technical Report CS-73-403 (

ftp://reports.stanford.edu/pub/cstr/reports/cs/tr/73/403/CS-TR-73-403.pdf
). December, 1973 — Примеч. автора.

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

Наконец, отметим следующее из раздела «Ошибки» справочной страницы GNU/Linux assert(3):

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

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

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

Справочная страница предостерегает нас от использования при вызовах

assert
выражений с побочными эффектами:

assert(*p++ == '\n');

Здесь побочным эффектом является увеличение указателя p как часть теста. Когда определен

NDEBUG
, аргумент выражения исчезает из исходного кода; он никогда не исполняется. Это может привести к неожиданной неудаче. Однако, как только при подготовке к отладке запрет на операторы проверки отменяется, все начинает снова работать! Такие проблемы трудно отследить.

12.2. Низкоуровневая память: функции

memXXX

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

mem
':

#include <string.h> /* ISO C */

void *memset(void *buf, int val, size_t count);

void *memcpy(void *dest, const void *src, size_t count);

void *memmove(void *dest, const void *src, size_t count);

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

Измена. За что ты так со мной

Дали Мила
1. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. За что ты так со мной

Неудержимый. Книга II

Боярский Андрей
2. Неудержимый
Фантастика:
городское фэнтези
попаданцы
5.00
рейтинг книги
Неудержимый. Книга II

Большие дела

Ромов Дмитрий
7. Цеховик
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Большие дела

Эксклюзив

Юнина Наталья
Любовные романы:
современные любовные романы
7.00
рейтинг книги
Эксклюзив

И только смерть разлучит нас

Зика Натаэль
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
И только смерть разлучит нас

Черкес. Дебют двойного агента в Стамбуле

Greko
1. Черкес
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Черкес. Дебют двойного агента в Стамбуле

Один на миллион. Трилогия

Земляной Андрей Борисович
Один на миллион
Фантастика:
боевая фантастика
8.95
рейтинг книги
Один на миллион. Трилогия

Ваше Сиятельство 8

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

Третье правило дворянина

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

Ваантан

Кораблев Родион
10. Другая сторона
Фантастика:
боевая фантастика
рпг
5.00
рейтинг книги
Ваантан

Невеста

Вудворт Франциска
Любовные романы:
любовно-фантастические романы
эро литература
8.54
рейтинг книги
Невеста

Романов. Том 1 и Том 2

Кощеев Владимир
1. Романов
Фантастика:
фэнтези
попаданцы
альтернативная история
5.25
рейтинг книги
Романов. Том 1 и Том 2

Кодекс Крови. Книга ХII

Борзых М.
12. РОС: Кодекс Крови
Фантастика:
боевая фантастика
попаданцы
5.00
рейтинг книги
Кодекс Крови. Книга ХII

Бальмануг. (Не) Любовница 2

Лашина Полина
4. Мир Десяти
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Бальмануг. (Не) Любовница 2