Читать книгу 📗 "Linux программирование в примерах - Роббинс Арнольд"
Этот случай поднимает важный момент относительно операторов проверки. Часто программисты ошибочно используют операторы проверки вместо проверки ошибок времени исполнения. В нашем случае тест '
array != NULLif (array == NULL) return -1;Тест '
size > 0sizelsearch()size <= 0Логика, стоящая за отменой оператора проверки, заключается в том, что дополнительные проверки могут снизить производительность программы и поэтому должны быть запрещены в заключительной версии программы. Хоар [123], однако, сделал такое замечание:
«В конце концов, абсурдно делать тщательные проверки безопасности при отладочных запусках, когда к результатам нет никакого доверия, а затем удалять их из финальных версий, когда ошибочный результат может быть дорогим или катастрофическим. Что бы мы подумали об энтузиасте-мореплавателе, который надевает свой спасательный жилет при тренировке на сухой земле и снимает его, как только выходит в море?»
С такими мнениями, наша рекомендация заключается во внимательном использовании операторов проверки- во-первых, для любого данного оператора проверки рассмотрите возможность использования вместо него проверки времени исполнения. Во-вторых, тщательно разместите свой оператор проверки, чтобы не было возражений против их оставления на своем месте лаже в финальной версии вашей программы.
Наконец, отметим следующее из раздела «Ошибки» справочной страницы GNU/Linux assert(3):
assert()NDEBUGЗнаменитый принцип неопределенности Гейзенберга из физики указывает, что чем более точно вы определите скорость частицы, тем менее точно вы определите ее положение, и наоборот. В терминах непрофессионала это означает что простой факт наблюдения частицы влияет на нее.
Сходное явление совершается в программировании, не связанном с физикой частиц: действие компилирования программы для отладки или запуска ее а режиме отладки может изменить поведение программы. В частности, первоначальная ошибка может исчезнуть. Такие ошибки в разговоре называют гейзенберговскими.
Справочная страница предостерегает нас от использования при вызовах
assert()assert(*p++ == 'n');Здесь побочным эффектом является увеличение указателя p как часть теста. Когда определен
NDEBUG12.2. Низкоуровневая память: функции
mem<i>XXX</i>()Несколько функций предоставляют возможность для работы с произвольными блоками памяти низкоуровневые службы. Все их имена начинаются с префикса '
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);void *memccpy(void *dest, const void *src, int val, size_t count);int memcmp(const void *buf1, const void *buf2, size_t count);void *memchr(const void *buf, int val, size_t count);12.2.1. Заполнение памяти:
memset()Функция
memset()unsigned charcountbufvoid *p = malloc(count);if (p != NULL) memset(p, 0, count);Однако
memset()buf12.2.2. Копирование памяти:
memcpy()memmove()memccpy()Три функции копируют один блок памяти в другой. Первые две функции отличаются в обработке перекрывающихся областей памяти; третья копирует память, но останавливается при встрече с определенным значением.
void *memcpy(void *dest, const void *src, size_t count)Это простейшая функция. Она копирует
countsrcdestdestvoid *memmove(void *dest, const void *src, size_t count)Подобно
memcpy()countsrcdestdestvoid *memccpy(void *dest, const void *src, int val, size_t count)Эта копирует байты из
srcdestvaldestcountvaldestvalNULLТеперь, в чем проблема с перекрывающейся памятью? Рассмотрим рис. 12.1.

Рис. 12.1. Перекрывающиеся копии
Целью является скопировать четыре экземпляра
struct xyzdata[0]data[3]data[3]data[6]data[3]data[0]data[3]data[6]