Строго говоря, есть одна действительно опасная функция. Это gets()
, потому что его ввод не контролируется программистом. Все остальные функции, упомянутые здесь, безопасны сами по себе. «Хорошие» и «плохие» сводятся к защитному программированию, а именно к предусловиям, постусловиям и стандартному коду.
Давайте возьмем strcpy()
например. У него есть некоторые предварительные условия, что программист должен выполнить перед вызовом функции. Обе строки должны быть действительными, указатели, отличные от NULL, должны содержать строки с нулевым символом в конце, а в месте назначения должно быть достаточно места для конечной длины строки в диапазоне size_t
. Кроме того, строки не могут перекрываться.
Это довольно много предварительных условий, и ни одно из них не проверено strcpy()
. Программист должен быть уверен, что они выполнены, или он должен явно проверить их с помощью дополнительного шаблонного кода перед вызовом strcpy()
:
n = DST_BUFFER_SIZE;
if ((dst != NULL) && (src != NULL) && (strlen(dst)+strlen(src)+1 <= n))
{
strcpy(dst, src);
}
Уже молча предполагая, что строки не перекрываются и оканчиваются нулем.
strncpy()
включает некоторые из этих проверок, но добавляет еще одно постусловие, которое программист должен позаботиться о после вызова функции, поскольку результат может не заканчиваться нулем.
strncpy(dst, src, n);
if (n > 0)
{
dst[n-1] = '\0';
}
Почему эти функции считаются "плохими"? Потому что им потребовался бы дополнительный шаблонный код для каждого вызова, чтобы действительно быть в безопасности, когда программист ошибается в правильности, и программисты склонны забывать этот код.
Или даже спорить с этим. Возьмите printf()
семью. Эти функции возвращают статус, который указывает на ошибку и успех. Кто проверяет, был ли успешным вывод в stdout или stderr? С аргументом, что вы ничего не можете сделать, когда стандартные каналы не работают. Ну, а как насчет спасения пользовательских данных и завершения программы с кодом ошибки, указывающим на ошибку? Вместо возможной альтернативы сбой и запись позже с поврежденными пользовательскими данными.
В условиях ограниченного времени и денег всегда возникает вопрос, сколько сетей безопасности вы действительно хотите и каков будет наихудший сценарий? Если это переполнение буфера, как в случае с str-функциями, то имеет смысл запретить их и, возможно, обеспечить функции-оболочки с уже существующими сетями безопасности.
Последний вопрос по этому поводу: почему вы уверены, что ваши «хорошие» альтернативы действительно хороши ?