Как избавиться от “небезопасных” предупреждений / ошибки в Visual Studio (strcpy, sprintf, strdup)

Я пытаюсь избавиться от некоторых предупреждений компилятора, которые говорят, что strcpy, sprintf, и т.д. небезопасны. Я добираюсь, почему они небезопасны, но я не могу думать о хорошем способе исправить код в стиле C++.

Вот выборка кода:

extList->names[i]=(char *)malloc(length*sizeof(char));
strcpy(extList->names[i],extName);                     // unsafe
// strncpy(extList->names[i],extName,length);          // also unsafe

Вот сообщение:

C4996: 'strcpy': Эта функция или переменная могут быть небезопасными. Рассмотрите использование strcpy_s вместо этого. Для отключения депрекации используйте _CRT_SECURE_NO_WARNINGS. Посмотрите справку онлайн для деталей.

Я не могу думать о безопасном способе скопировать данные в C++, не зная, что длина материала копирует. Я знаю, что существует strlen (), но это также небезопасно, так как он принимает (возможно, неправильно), что данные завершаются пустым указателем.

Также:

// used to concatenate:
sprintf(extStr,"%s%s",platExtStr,glExtStr);

C4996: 'sprintf': Эта функция или переменная могут быть небезопасными. Рассмотрите использование sprintf_s вместо этого. Для отключения депрекации используйте _CRT_SECURE_NO_WARNINGS. Посмотрите справку онлайн для деталей.

Используя станд.:: строка для конкатенации достаточно легка, но затем я должен получить данные в extStr так или иначе (и не использующий strcpy, lol). Строка:: c_str () функция возвращает указатель на немодифицируемые данные, таким образом, я не могу просто установить extStr, равный ему. (И я даже не уверен, должен ли c_str () указатель удалить, обратился к нему позже? Это выделяет место, использующее "новый"?)

Совет относительно этого материала? Это - часть 10 000 файлов строки, это не является моим..., таким образом, я не точно увлечен перезаписью вещи в C++ путь.

21
задан jrh 12 October 2016 в 13:00
поделиться

5 ответов

На самом деле вам не нужны прагмы, чтобы отключить их.

Для win32/msvc, в ProjectProperties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions, добавьте следующие макросы:

_CRT_SECURE_NO_DEPRECATE  
_CRT_NONSTDC_NO_DEPRECATE

Или вы можете передать их в параметрах командной строки (-D_CRT_SECURE_NO_DEPRECATE). Возможно, вы можете #define их в начале определенных *.cpp файлов. Кроме того, их, вероятно, больше (см. crtdefs.h - похоже, их много...). Подобные предупреждения обычно сообщают, с помощью каких макросов их можно отключить - просто прочитайте вывод компилятора.

35
ответ дан 29 November 2019 в 06:36
поделиться

В первом примере вы уже знаете длину. Поскольку вы не выделяете length + 1 байт, я предполагаю, что length ВКЛЮЧАЕТ нулевой ограничитель. В этом случае просто std :: copy строка: std :: copy (extName, extName + length, expList-> names [i]);

Во втором примере предполагается, что исходные строки заканчиваются нулем, вы можете вычислить длину целевой строки и снова использовать std :: copy для объединения вручную, или вы можете использовать std :: string и std: : скопируйте из результатов c_str в пункт назначения (опять же при условии, что вы выделили для него достаточно места).

c_str () не выделяет память, которая требует внешнего удаления.

Наконец, обратите внимание, что sizeof (char) всегда будет равным единице, поэтому он является избыточным в вашем malloc, хотя количество битов в этом символе может не равняться 8 (см. CHAR_BIT ) .

4
ответ дан 29 November 2019 в 06:36
поделиться

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

Example:


char* StringCopy(char* Destination, const char* Source, size_t DestinationSize)
{
#ifdef _MSC_VER
  return strcpy_s(Destination, Source, DestinationSize);
#else
  if(!(strlen(Source) >= DestinationSize))
     return strcpy(Destination, Source);
  else
     return 0x0;
#endif
}
2
ответ дан 29 November 2019 в 06:36
поделиться

Вы знаете, сколько копировать - вы выделили для этого место!

Неужели вы не захотите скопировать больше места, чем выделено вами?

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

dest = malloc(len);         // note: where did we get len?
if ( dest is null )  panic!  // note: malloc can fail
strncpy(dest, src, len);
dest[len-1] =0;

. Это немного беспорядочно, и, как уже отмечалось, используется метод strncpy (), который изначально был разработан для полей фиксированной ширины, а не для строк. Однако это действительно так.

Существуют такие методы, как strdup () и strlcpy (), которые могут нам помочь.

Мои рекомендации:

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

2). При копировании строк вам необходимо обеспечить следующее:

  • Защитить себя от неверного ввода, например, незавершенной или слишком длинной строки.
  • Защитите себя от сбоев malloc,
  • Настоятельно предпочтите копии подсчитанного количества символов копированию, пока мы не увидим нуль
  • Если вы утверждаете, что построили строку, то обязательно убедитесь, что вы завершили ее нулевым значением

Если strlcpy () доступен в вашей среде, тогда вы могли бы его использовать, иначе почему бы не написать свою собственную небольшую полезную функцию? Тогда, если есть предупреждения только в той функции, которую вы локализовали, тогда проблема.

5
ответ дан 29 November 2019 в 06:36
поделиться

Если переносимость не волнует, можно использовать 'strcpy_s'.

2
ответ дан 29 November 2019 в 06:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: