C4996 (функция небезопасная) предупреждение для strcpy, но не для memcpy
Я пишу код в VS2010, и я вижу, что после компиляции компилятор дает мне предупреждение C4996 ( "Эта функция или переменная может быть небезопасной" ) для вызовов strcpy и sprintf.
Однако я не мог получить похожие предупреждения для memcpy (и, возможно, в коде есть несколько подобных "небезопасных" вызовов функций)
int _tmain(int argc, _TCHAR* argv[])
{
char buf1[100], buf2[100];
strcpy (buf1, buf2); // Warning C4996 displayed here asking to use strcpy_s instead
memcpy (buf1, buf2, 100); // No warning here asking to use memcpy_s
memcpy_s(buf1, 100, buf2, 100);
return 0;
}
Почему это так? Как включить предупреждение C4996 для всех возможных небезопасных вызовов в моем коде?
Ответы
Ответ 1
В общем, для компиляции кода C вам нужен соответствующий C-компилятор. Visual Studio является несоответствующим компилятором С++.
Вы получаете предупреждение, потому что Visual Studio плохо. См. это.
C4996 появляется всякий раз, когда вы используете функцию, которую Microsoft считает устаревшей. По-видимому, Microsoft решила, что они должны диктовать будущее языка C, а не рабочую группу ISO C. Таким образом, вы получаете ложные предупреждения для совершенно точного кода. Проблема заключается в компиляторе.
Нет ничего плохого в функции strcpy(), которая является мифом. Эта функция существует около 30-40 лет, и каждая ее часть должным образом документирована. Итак, что делает функция и что она не делает, это не должно быть неожиданностью, даже для начинающих программистов на C.
Что strcpy делает и не делает:
- Он копирует строку с нулевым завершением в другую ячейку памяти.
- Он не несет никакой ответственности за обработку ошибок.
- Он не исправляет ошибки в приложении-вызывающем.
- Он не несет никакой ответственности за обучение программистов C.
Из-за последнего замечания выше вы должны знать следующее перед вызовом strcpy:
- Если вы передаете строку неизвестной длины в strcpy, не проверяя ее длину заранее, у вас есть ошибка в приложении-вызывающем.
- Если вы передаете некоторый фрагмент данных, который не заканчивается на
\0
, у вас есть ошибка в приложении-вызывающем.
- Если вы передадите два указателя на strcpy(), которые указывают на перекрывающиеся ячейки памяти, вы вызываете поведение undefined. Это означает, что у вас есть ошибка в приложении-получателе.
Например, в коде, который вы опубликовали, вы никогда не инициализировали массивы, поэтому ваша программа, скорее всего, сработает и сгорит. Эта ошибка никоим образом не связана с функцией strcpy() и не будет решена путем замены strcpy() на что-то еще.
Ответ 2
strcpy
небезопасно, если отсутствует завершающий NUL
, так как он может копировать больше символов, чем соответствовать области назначения. При memcpy
количество скопированных байтов фиксировано.
Функция memcpy_s
на самом деле упрощает программистам делать это неправильно - вы пропускаете две длины, и она использует меньшую из них, и все, что вы получаете, - это код ошибки, который можно игнорировать без лишних усилий. Вызов memcpy
требует заполнения параметра size
, который должен заставить программистов подумать о том, что передать.
Ответ 3
Вы получаете это предупреждение, потому что не передавать длину строки и полагаться на завершение \0
небезопасны, поскольку они могут вызвать переполнение буфера. В memcpy вы проходите длину, чтобы не переполнять проблему.
Вы можете использовать что-то вроде
#ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable:4996)
#endif
strcpy... ; // Code that causes unsafe warning
#ifdef _MSC_VER
# pragma warning(pop)
#endif
Если вы не беспокоитесь о переносимости, вы можете использовать такие альтернативы, как strcpy_s
и т.д.
Ответ 4
Поскольку strcpy
и sprintf
действительно являются небезопасными функциями, это зависит от содержимого строки, а не от переполнения. Вместо этого вы должны использовать strncpy
и snprintf
, чтобы убедиться, что он не перезаписывает память.
Пока memcpy
не в этом случае, он имеет длину, поэтому он не перезаписывает память, пока длина правильная.
Ответ 5
Включить в заголовок "stdafx.h"
определение
#define _CRT_SECURE_NO_WARNINGS
Что касается разницы strcpy
и memcpy
, то последняя функция имеет третий параметр, который явно определяет, сколько символов нужно скопировать. Первая функция не имеет информации о том, сколько символов будет скопировано из исходной строки в строку назначения, поэтому в общем случае существует вероятность того, что память, выделенная для целевой строки, будет перезаписана.
Ответ 6
Предупреждение означает, что функция устарела и не будет доступна в будущих версиях: http://msdn.microsoft.com/en-US/en-en/library/ttcz0bys.aspx Вы не можете добавить другие функции в список отказов Microsoft.
Причина устаревания "небезопасна", но это отличается от вашего предположения "C4496 показывает вам все небезопасные функции".
Ответ 7
Причина, по которой вы получаете предупреждение на sprintf
и strcpy
, а не на memcpy
, заключается в том, что memcpy
имеет параметр длины, который ограничивает количество копий памяти. Для strcpy
и memcpy
вход должен быть завершен с помощью \0
. Если нет, это будет продолжаться за гранью. Вы можете ограничить это, используя функции snprintf
и strncpy
. Они неявно ограничивают, сколько можно скопировать.
Обратите внимание, что microsoft устарело snprintf
, поэтому вместо этого вы должны использовать функцию замены _snprintf
. Однако это специфическая функция MSVC.
Я бы посоветовал покончить с буферами char *
и переключиться на С++, используя stl-контейнер, например std::string
. Это сэкономит вам массу отладочных головных болей и сохранит ваш код портативным.