fopen已弃用警告


69

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.'

我该如何预防?

Answers:


130

看起来Microsoft已经弃用了许多使用缓冲区来提高代码安全性的调用。但是,他们提供的解决方案不是便携式的。无论如何,如果您对使用其调用的安全版本(例如fopen_s)不感兴趣,则需要在包含的头文件之前放置_CRT_SECURE_NO_DEPRECATE的定义。例如:

#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>

也可以将预处理器指令添加到您的项目设置中,以对项目下的所有文件生效。为此,将_CRT_SECURE_NO_DEPRECATE添加到项目属性->配置属性-> C / C ++->预处理程序->预处理程序定义


9
您可能应该执行以下操作:#ifdef _WIN32 #define _CRT_SECURE_NO_DEPRECATE #endif #include <stdio.h>因为其他平台不需要在编译时定义该代码。
markwatson

1
@markwatson一个更好的警卫是检查#ifdef _MSC_VER
MicroVirus

30

好吧,您可以添加:

#pragma warning (disable : 4996)

在使用fopen之前,但是您是否考虑过按照警告提示使用fopen_s?它返回一个错误代码,允许您检查函数调用的结果。

仅禁用不推荐使用的功能警告的问题在于,Microsoft可能会在更高版本的CRT中删除有问题的功能,从而破坏您的代码(如注释中所述,在这种情况下,使用fopen不会发生这种情况,因为它是C&C ++ ISO标准)。


39
如果Microsoft不再希望实现C或C ++标准,则“ Microsoft可能会在更高版本的CRT中删除有问题的功能”。
史蒂夫·杰索普

5
有些人也以非MS平台为目标。而且,由于其中许多_s函数,实际上并没有明显的安全性增益。
2011年

15
对于未来的Google:In this context, "deprecated" just means that a function's use is not recommended; it does not indicate that the function is scheduled to be removed from the CRT.- MSDN ++++
纳文

1
@SteveJessop他们已经有意并愿意打破标准。看到这个
2014年

5
在VS2013中,我需要使用,#pragma warning(disable:4996)因为建议的_CRT_SECURE_NO_WARNINGS_CRT_SECURE_NO_DEPRECATE两者都不起作用。在#define小号似乎在其他环境中工作,所以抬头,这似乎是不一致实现。
Bill Weinman

13

这只是微软的厚脸皮。“不推荐使用”表示标准委员会/组织在将来的标准语言/标准库版本中可能未提供的语言功能。无论该建议有多充分的依据,它都不会或不应该表示“我们单方面认为您不应该使用它”。


14
英文单词“ deprecate”的含义恰恰是第二件事:“我们认为您不应该使用它”。但是用计算机的话来说,它的含义最近变得很弱,“使用它可能不明智,因为我们正在考虑删除它,并且我们提供了一些我们认为更好的东西”。
史蒂夫·杰索普

9

如果您的代码是针对其他操作系统(例如Mac OS X,Linux)的,则可以使用以下代码:

#ifdef _WIN32
#define _CRT_SECURE_NO_DEPRECATE
#endif

5

我正在使用VisualStdio2008。在这种情况下,我经常设置 Preprocessor Definitions

菜单\项目\ [ProjectName]属性... Alt + F7

如果单击此菜单或在项目窗口中按Alt + F7,则可以看到“属性页”窗口。

然后查看窗口左侧的菜单。

配置属性\ C / C ++ \预处理程序

然后添加_CRT_SECURE_NO_WARNINGS\预处理程序定义


请首先查看此“如何 解答”。显然,您可以在此处添加答案。但是您需要在回答之前理解一些要点。首先,不要添加先前使用相同代码或建议添加的答案。其次,如果用户已经非常明确地询问了问题及其解决方案,请不要添加过于复杂的答案。第三,如果您想提出有关答案或问题的任何建议,可以添加评论。
ankit suthar

这是在Visual Studio 2017中对我#define有用的唯一答案。留下了许多C4996错误。(@ankitsuthar,您的评论对我来说似乎放错了地方。这个答案很简洁,有效,并且在其他细节上也有所不同。)
Bob Stein

4

考虑使用可移植性库,例如glibapache Portable Runtime。这些通常可为此类呼叫提供安全,便携式的替代方法。这也是一件好事,因为这些不安全的调用在大多数现代环境中已被弃用。


1
C标准功能是Microsoft一次性,不完全符合标准,不可移植的可选附件K功能的便携式替代方案。fopen_s()fopen()
安德鲁·亨利

1

如果要在许多平台上使用它,则可以使用注释定义如下:

#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

您复杂的#IF仅适用于平台,不适用于编译器版本。如何#if (defined(_MSC_VER) && (_MSC_VER >= 1600) ) ... #ELSE ...这应该涵盖所有的情况下,对吧?
riderBill

_MSC_VER = 1600可能不是弃用fopen()等的第一个版本。这是我遇到此问题的第一个版本。
riderBill

像MSVC的第一个版本的(一些)的安全功能看起来是2005年,_MSC_VER = 1400
riderBill

1

对于使用Visual Studio 2017版本的用户,似乎运行不安全操作所需的预处理器定义已更改。改用:

#define _CRT_SECURE_NO_WARNINGS

然后它将编译。


1
这似乎不适用于我。仍然会出现的编译错误freopen
列维·罗伯茨

1
@LeviRoberts您必须将此定义放在文件的最顶部,包括一些头文件时会生成错误
jrh

1

Microsoft的许多安全功能,包括fopen_s(),都是C11的一部分,因此它们现在应该是可移植的。您应该认识到安全功能在异常行为和返回值方面有所不同。另外,您还需要注意,尽管这些功能已标准化,但它是标准(附件K)的可选部分,至少glibc(Linux上的默认设置)和FreeBSD的libc没有实现。

但是,我为此问题奋斗了几年。我在这里发布了更多的转换宏集,如果遇到直接的问题,请将以下代码放入包含文件中,并将其包含在源代码中:

#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

当然,这种方法不会实现预期的异常行为。


1
_s通常,MS与C11边界检查接口不同。有些具有相同的特性,有些则没有。由于该接口是可选的,因此几乎没有实现支持该接口,因为它基本上是不必要的。您的代码是C ++,而不是您在文本中引用的C。
对于这个网站来说太老实了

@Olaf:嗯。除了指出我的异常行为警告之外,我无法解决边界检查问题。
riderBill

没错,我引用了C11标准(与C ++ 14或17相反)。这些功能在Microsoft C ++编译器的最新版本中可用。事实证明,附件K在MSVS之外并未得到广泛支持。乔纳森·莱夫勒(Jonathan Leffler)在这里评论说,MS版本实际上与附件K规范不匹配。便携性非常重要。
riderBill

1
如果您能完整阅读我的评论,我将不胜感激。MSVC并不是真正使用BCI,而是自己使用。自从至少18年以来,MSVC一直没有遵从本标准,并且非常明确地不打算这样做,至少包括C99强制性功能(例如VLA),这种功能已经被多年以来的每个现代编译器所支持(包括主要的嵌入式功能)。
对于这个网站来说太老实了

发问者标记为Visual C ++。我从更大的C ++文件复制了代码。对于C语言,我想包含将为stdio.hstring.h(尽管上面的代码中未使用字符串)。我不需要using名称空间std; 语句-在C语言中有效吗?我在想内联extern ...应该是C中的静态内联,以避免链接器问题。这些天我没有写太多的C代码。如果我写错了,请添加评论。
riderBill

0

我也遇到同样的问题。当我尝试添加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 ++”->“预编译头”->“在预编译头中选择不使用预编译头”。
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.