Устарело предупреждение
В компиляторе Visual Studio 2005 C++ я получаю следующее предупреждение, когда мой код использует fopen и такие вызовы.
1>foo.cpp(5) : warning C4996: 'fopen' was declared deprecated
1> c:\program files\microsoft visual studio 8\vc\include\stdio.h(234) : see declaration of 'fopen'
1> Message: 'This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_DEPRECATE. See online help for details.'
Как мне это предотвратить?
11 ответов
Похоже, что Microsoft устарела много вызовов, которые используют буферы для повышения безопасности кода. Однако предлагаемые ими решения не являются переносимыми. В любом случае, если вы не заинтересованы в использовании защищенной версии их вызовов (например, fopen_s), вам нужно поместить определение _CRT_SECURE_NO_DEPRECATE перед включенными заголовочными файлами. Например:
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
Директива препроцессора также может быть добавлена в настройки вашего проекта, чтобы применить ее ко всем файлам в проекте. Для этого добавьте _CRT_SECURE_NO_DEPRECATE в Свойства проекта -> Свойства конфигурации -> C/C++ -> Препроцессор -> Определения препроцессора.
Ну, вы могли бы добавить:
#pragma warning (disable : 4996)
прежде чем использовать fopen, но рассматривали ли вы возможность использования fopen_s, как следует из предупреждения? Возвращает код ошибки, позволяющий проверить результат вызова функции.
Проблема с простым отключением предупреждений об устаревших функциях заключается в том, что Microsoft может удалить соответствующую функцию в более поздней версии CRT, нарушая ваш код (как указано ниже в комментариях, в этом случае это не произойдет с fopen, потому что это часть стандарты C & C++ ISO).
Это просто Microsoft дерзкая. "Устаревший" подразумевает языковую функцию, которая может отсутствовать в будущих версиях стандартного языка / стандартных библиотек, как предписано комитетом по стандартам. Это не означает или не должно означать "мы, в одностороннем порядке, не думаем, что вы должны его использовать", независимо от того, насколько обоснован этот совет.
Если ваш код предназначен для другой ОС (например, Mac OS X, Linux), вы можете использовать следующее:
#ifdef _WIN32
#define _CRT_SECURE_NO_DEPRECATE
#endif
Я использую VisualStdio 2008. В этом случае я часто устанавливаю Preprocessor Definitions
Меню \ Проект \ [ProjectName] Свойства... Alt+F7
Если щелкнуть это меню или нажать Alt + F7 в окне проекта, вы увидите окно "Страницы свойств".
Затем посмотрите меню слева от окна.
Свойства конфигурации \ C/C++ \ Препроцессор
Затем добавьте _CRT_SECURE_NO_WARNINGS
\ Определения препроцессора.
Подумайте об использовании библиотеки переносимости, такой как glib или переносимая среда выполнения Apache. Они обычно предоставляют безопасные, портативные альтернативы таким звонкам. Это тоже хорошо, потому что эти небезопасные вызовы устарели в большинстве современных сред.
Если вы хотите, чтобы он использовался на многих платформах, вы можете, как прокомментировано, использовать следующее:
#if defined(_MSC_VER) || defined(WIN32) || defined(_WIN32) || defined(__WIN32__) \
|| defined(WIN64) || defined(_WIN64) || defined(__WIN64__)
errno_t err = fopen_s(&stream,name, "w");
#endif
#if defined(unix) || defined(__unix) || defined(__unix__) \
|| defined(linux) || defined(__linux) || defined(__linux__) \
|| defined(sun) || defined(__sun) \
|| defined(BSD) || defined(__OpenBSD__) || defined(__NetBSD__) \
|| defined(__FreeBSD__) || defined __DragonFly__ \
|| defined(sgi) || defined(__sgi) \
|| defined(__MACOSX__) || defined(__APPLE__) \
|| defined(__CYGWIN__)
stream = fopen(name, "w");
#endif
Многие из безопасных функций Microsoft, включая fopen_s(), являются частью C11, поэтому они должны быть переносимыми. Вы должны понимать, что функции безопасности отличаются поведением исключений, а иногда и возвращаемыми значениями. Кроме того, вы должны знать, что хотя эти функции стандартизированы, это необязательная часть стандарта (Приложение K), которую, по крайней мере, glibc (по умолчанию в Linux) и libc FreeBSD не реализуют.
Тем не менее, я боролся с этой проблемой в течение нескольких лет. Я разместил здесь большой набор макросов преобразования ., Для вашей непосредственной проблемы, поместите следующий код во включаемый файл и включите его в ваш исходный код:
#pragma once
#if !defined(FCN_S_MACROS_H)
#define FCN_S_MACROS_H
#include <cstdio>
#include <string> // Need this for _stricmp
using namespace std;
// _MSC_VER = 1400 is MSVC 2005. _MSC_VER = 1600 (MSVC 2010) was the current
// value when I wrote (some of) these macros.
#if (defined(_MSC_VER) && (_MSC_VER >= 1400) )
inline extern
FILE* fcnSMacro_fopen_s(char *fname, char *mode)
{ FILE *fptr;
fopen_s(&fptr, fname, mode);
return fptr;
}
#define fopen(fname, mode) fcnSMacro_fopen_s((fname), (mode))
#else
#define fopen_s(fp, fmt, mode) *(fp)=fopen( (fmt), (mode))
#endif //_MSC_VER
#endif // FCN_S_MACROS_H
Конечно, этот подход не реализует ожидаемое поведение исключения.
Для тех, кто использует версию Visual Studio 2017, похоже, что определение препроцессора, необходимое для выполнения небезопасных операций, изменилось. Используйте вместо:
#define _CRT_SECURE_NO_WARNINGS
Это будет скомпилировано тогда.
У меня тоже такая же проблема. Когда я пытаюсь добавить библиотеку opencv
#include <opencv\cv.h>
Я получил не предупреждение, а ошибку.
error C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. c:\program files (x86)\opencv\build\include\opencv2\flann\logger.h
Я также использовал директивы препроцессора, как уже упоминалось. Но это не решило проблему.
Я решил это следующим образом:
- Перейдите в Свойства -> C/C++ -> Предварительно скомпилированные заголовки -> Выберите Не использовать предварительно скомпилированные заголовки в предварительно скомпилированных заголовках.
Чтобы улучшить ответ выше, мне помогает этот макрос
#include "stdio.h"
#if (defined(_MSC_VER) && (_MSC_VER >= 1400) )
static inline
FILE* fn_fopen(const char* fname, const char* mode)
{
FILE* fptr;
errno_t err = fopen_s(&fptr, fname, mode);
if (err != 0) {
return NULL;
}
return fptr;
}
#define _fopen_(fname, mode) fn_fopen((fname), (mode))
#else
#define _fopen_(fname, mode) fopen((fname), (mode))
#endif
Затем вы можете открыть файл
FILE* fp = _fopen_(filename, "rb");
if (fp == NULL) {
/* Cannot open the file */
}
Мне не нравится переопределять fopen() и вместо этого использовать собственный макрос. Это позволяет избежать некоторых потенциальных проблем.