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 для всех возможных небезопасных вызовов в моем коде?

В общем, для компиляции кода C вам нужен соответствующий C-компилятор. Visual Studio является несоответствующим компилятором C ++.

Вы получаете предупреждение, потому что Visual Studio плохо. Смотрите это .

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

Нет ничего плохого в функции strcpy (), это миф. Эта функция существует около 30-40 лет, и каждая ее часть должным образом документирована. Итак, что делает функция и что она не делает, это не должно быть неожиданностью, даже для начинающих программистов C.

Что strcpy делает и не делает:

  • Он копирует строку с нулевым символом в другую ячейку памяти.
  • Он не несет никакой ответственности за обработку ошибок.
  • Он не исправляет ошибки в приложении вызывающего абонента.
  • Он не несет никакой ответственности за обучение программистов C.

Из-за последнего замечания выше вы должны знать следующее перед вызовом strcpy:

  • Если вы передадите строку неизвестной длины в strcpy, не проверяя ее длину заранее, у вас есть ошибка в приложении-вызывателе.
  • Если вы передадите некоторый fragment данных, который не заканчивается на \0 , у вас есть ошибка в приложении-вызывателе.
  • Если вы передадите два указателя на strcpy (), которые указывают на перекрывающиеся ячейки памяти, вы вызываете неопределенное поведение. Это означает, что у вас есть ошибка в приложении вызывающего абонента.

Например, в коде, который вы опубликовали, вы никогда не инициализировали массивы, поэтому ваша программа, скорее всего, сработает и сгорит. Эта ошибка никоим образом не связана с функцией strcpy () и не будет решена путем замены strcpy () на что-то еще.

strcpy небезопасен, если отсутствует конечный NUL , поскольку он может копировать больше символов, чем соответствовать области назначения. С memcpy число скопированных байт фиксировано.

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

Вы получаете это предупреждение, потому что не передавая длину строки и полагаясь на завершение \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 т. Д.

Включить в определение заголовка "stdafx.h"

 #define _CRT_SECURE_NO_WARNINGS 

Что касается разницы в strcpy и memcpy то последняя функция имеет третий параметр, который явно указывает, сколько символов нужно скопировать. Первая функция не имеет информации о том, сколько символов будет скопировано из исходной строки в строку назначения, поэтому в общем случае существует вероятность того, что память, выделенная для целевой строки, будет перезаписана.

Поскольку strcpy и sprintf действительно являются небезопасными функциями, это зависит от содержимого строки, а не от переполнения. Вместо этого вы должны использовать strncpy и snprintf чтобы убедиться, что он не перезаписывает память.

Хотя memcpy не в этом случае, он имеет длину, поэтому он не перезаписывает память до тех пор, пока длина верна.

Предупреждение предупреждает, что функция устарела и не будет доступна в будущих версиях: http://msdn.microsoft.com/en-US/en-en/library/ttcz0bys.aspx Вы не можете добавить другие функции в устаревание список Microsoft.

Причина устаревания «небезопасна», но это отличается от вашего предположения «C4496 показывает вам все небезопасные функции».

Причина, по которой вы получаете предупреждение о sprintf и strcpy , а не на memcpy , заключается в том, что memcpy имеет параметр длины, который ограничивает объем памяти, которую вы копируете. Для strcpy и memcpy вход должен быть завершен с помощью \0 . Если нет, это будет продолжаться за гранью. Вы можете ограничить это, используя функции snprintf и strncpy . Они неявно ограничивают, сколько можно скопировать.

Обратите внимание, что Microsoft не рекомендует использовать snprintf , поэтому вместо этого вы должны использовать функцию замены _snprintf . Однако это специфическая функция MSVC.

Я бы посоветовал уничтожить все буферы char * и переключиться на C ++, используя stl-контейнер, например std::string . Это избавит вас от многих отладочных головных болей и сохранит ваш код переносимым.