Почему никакие проверки работоспособности в устаревшем strcpy()

Ниже приведена самая популярная реализация strcpy в традиционных системах. Почему dest и src не проверяются на NULL в начале? Я слышал однажды, что в прежние времена память была ограничена, поэтому короткий код всегда был предпочтительным. Будете ли вы реализовывать strcpy и другие подобные функции с проверкой указателя NULL в начале сейчас? Почему бы и нет?

char *strcpy(char *dest, const char *src)
{
   char *save = dest;
   while(*dest++ = *src++);
   return save;
}

Ответ 1

NULL - плохой указатель, но это также (char*)0x1. Должен ли он также проверить это? По моему мнению (я не знаю окончательной причины, почему), проверки работоспособности в такой операции низкого уровня не учитываются. strcpy() настолько фундаментален, что к нему следует относиться как к инструкции asm, и при необходимости вы должны делать свои собственные проверки работоспособности. Только мои 2 цента:)

Ответ 2

Нет никаких проверок здравомыслия, потому что одна из наиболее важных идеологий C - это то, что разработчик обеспечивает здравомыслие. Когда вы предполагаете, что разработчик работоспособен, вы получаете язык, который можно использовать для чего угодно и где угодно.

Это не явно заявленная цель - вполне возможно, что кто-то придумает реализацию, которую делает для этого, и многое другое. Может, они и есть. Но я сомневаюсь, что многие люди, привыкшие к C, будут кричать, чтобы использовать его, так как им нужно было бы поместить чеки в любом случае, если бы у них был шанс, что их код будет перенесен на более обычную реализацию.

Ответ 3

Весь язык C написан с девизом "Мы будем вести себя правильно, если программист знает, что он делает". Ожидается, что программист узнает, чтобы сделать все проверки, которые ему нужно сделать. Это не просто проверка на NULL, это гарантирует, что dest указывает на достаточную выделенную память для хранения src, проверяя возвращаемое значение fopen, чтобы убедиться, что файл действительно успешно открыт, зная, когда memcpy является безопасным и когда требуется memmove и т.д.

Получение strcpy для проверки NULL не изменит языковой парадигмы. Вам все равно необходимо убедиться, что dest указывает на достаточное пространство - и это то, что strcpy не может проверить без изменения интерфейса. Вам также необходимо убедиться, что src '\0' -терминирован, что еще раз strcpy не может проверить.

Существуют некоторые стандартные функции библиотеки C, которые проверяют значение NULL: например, free(NULL) всегда безопасно. Но в целом, C ожидает, что вы узнаете, что вы делаете.

[С++ обычно избегает библиотеки <cstring> в пользу std::string и друзей.]

Ответ 4

  • Обычно библиотека лучше разрешает вызывающему абоненту решать, что ему нужно, чтобы семантика отказа была. Что бы вы имели strcpy, если любой аргумент NULL? Безмолвно ничего не делать? Не удалось выполнить assert (что не является вариантом в не-отладочных сборках)?

  • Это проще для выбора, чем для отказа.. Тривиально писать собственную оболочку вокруг strcpy, которая проверяет входные данные и использует их вместо этого. Если, однако, библиотека сделала это сама, у вас не было бы выбора не выполнять эти проверки, не перепрограммируя strcpy. (Например, вы, возможно, уже знаете, что аргументы, которые вы передаете в strcpy, не являются NULL, и вам может быть интересно, если вы вызываете его в узком цикле или обеспокоены минимизацией использования энергии. ) В общем, лучше ошибиться на стороне предоставления большей свободы (даже если эта свобода несет дополнительную ответственность).

Ответ 5

Наиболее вероятная причина: поскольку strcpy не указан для работы с входами NULL (т.е. его поведение в этом случае равно undefined).

Итак, что должен сделать разработчик библиотеки, если передан NULL? Я бы сказал, что самое лучшее, что можно сделать, это запустить приложение. Подумайте об этом так: авария - довольно очевидный признак того, что что-то пошло не так... молча игнорируя вход NULL, с другой стороны, может замаскировать ошибку, которую будет намного сложнее обнаружить.

Ответ 6

Проверки NULL не были реализованы, поскольку самые ранние объекты C поддерживали надежную защиту памяти. Когда процесс попытался прочитать или записать в NULL, контроллер памяти будет сигнализировать CPU о попытке доступа к внедиапазонной памяти (нарушение сегментации), и ядро ​​уничтожит процесс нарушения.

Это был хороший ответ, потому что код, пытающийся прочитать или записать указатель NULL, сломан; единственный ответ - переписать код для проверки возвращаемых значений из malloc(3) и друзей и предпринять корректирующие действия. К тому моменту, когда вы пытаетесь использовать указатели для нераспределенной памяти, уже слишком поздно принимать правильное решение о том, как исправить ситуацию.

Ответ 7

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

Ответ 8

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

Функция strcpy() копирует строку, на которую указывает src (включая завершающий символ "\ 0" ) в массив, на который указывает dest. Строки не должны пересекаться, а целевая строка dest должна быть достаточно большой, чтобы получить копию.

Теперь, если предварительное условие не выполнено, все может быть undefined.

Теперь я бы включил проверку NULL в свой strcpy. Я предпочел бы еще один safe_strcpy, обеспечив безопасность приоритета, который я обязательно включил бы NULL-проверки и обработал бы условия переполнения. И, соответственно, мое предварительное условие изменяется.

Ответ 9

Для него просто нет семантики ошибок. В частности, нет возможности вернуть strcpy значение ошибки. C99 просто заявляет:

Функция strcpy возвращает значение s1.

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

Все это добровольно, я думаю, поскольку strcpy заменяется большинством компиляторов очень эффективным ассемблером напрямую. Проверка ошибок выполняется для вызывающего.