【问题标题】:fopen deprecated warningfopen 弃用警告
【发布时间】:2008-08-18 09:38:58
【问题描述】:

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

如何防止这种情况发生?

【问题讨论】:

    标签: visual-c++ fopen deprecated


    【解决方案1】:

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

    #define _CRT_SECURE_NO_DEPRECATE
    #include <stdio.h>
    

    预处理器指令也可以添加到您的项目设置中,以影响项目下的所有文件。为此,将 _CRT_SECURE_NO_DEPRECATE 添加到 Project Properties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions

    【讨论】:

    • 你可能应该这样做:#ifdef _WIN32 #define _CRT_SECURE_NO_DEPRECATE #endif #include 因为其他平台不需要在编译时定义。
    • @markwatson 更好的保护措施是检查#ifdef _MSC_VER
    • 我正在使用 Visual Studio 2019 并将“#define _CRT_SECURE_NO_DEPRECATE”添加到我的代码中并没有帮助。我必须进入项目设置并在 C/C++ --> Preprocessor --> Preprocessor Definitions 下手动在字符串末尾添加“;_CRT_SECURE_NO_DEPRECATE”。
    【解决方案2】:

    你可以添加一个:

    #pragma warning (disable : 4996)
    

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

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

    【讨论】:

    • “Microsoft 可能会在 CRT 的更高版本中删除相关功能” - 如果他们不再希望实现 C 或 C++ 标准。
    • 有些人也针对非 MS 平台。并且有很多这样的 _s 函数,并没有真正显着的安全增益。
    • 对于未来的谷歌员工: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 ++++
    • @SteveJessop 他们已经有意并愿意打破标准。见this
    • 在 VS2013 中我需要使用 #pragma warning(disable:4996),因为建议的 _CRT_SECURE_NO_WARNINGS_CRT_SECURE_NO_DEPRECATE 都不起作用。 #defines 似乎在其他情况下也有效,因此请注意,这似乎是不一致的实施。
    【解决方案3】:

    这只是微软厚脸皮。根据标准委员会的规定,“已弃用”表示标准语言/标准库的未来版本中可能不会提供的语言功能。它并不或不应该意味着“我们单方面认为您不应该使用它”,无论该建议多么有根据。

    【讨论】:

    • 英文单词“deprecate”的意思恰恰是第二件事:“我们认为你不应该使用它”。但在计算机用语中,它的含义最近变得更弱了,“使用它可能并不明智,因为我们正在考虑删除它,并且我们提供了我们认为更好的东西”。跨度>
    【解决方案4】:

    如果您的代码适用于不同的操作系统(如 Mac OS X、Linux),您可以使用以下代码:

    #ifdef _WIN32
    #define _CRT_SECURE_NO_DEPRECATE
    #endif
    

    【讨论】:

      【解决方案5】:

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

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

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

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

      配置属性\C/C++\预处理器

      然后将 _CRT_SECURE_NO_WARNINGS 添加到 \Preprocessor Definitions

      【讨论】:

      • 请先看这个how-to-answer这个问题之前回答过,显然,你可以在这里添加你的答案。但是在回答之前,您需要了解一些要点。首先,不要添加以前使用相同代码或建议添加的答案。其次,如果用户已经非常具体地询问了问题以及他需要解决什么问题,请不要添加过于复杂的答案。第三,如果您想对答案或问题提出任何建议,可以添加评论。
      • 这是在 Visual Studio 2017 中对我有用的唯一答案。#define 留下了很多 C4996 错误。 (@ankitsuthar 你的评论对我来说似乎放错了地方。这个答案简洁,有效,并且在重要细节上与其他答案不同。)
      【解决方案6】:

      考虑使用像glibapache portable runtime 这样的可移植库。这些通常为此类调用提供安全、便携的替代方案。这也是一件好事,因为这些不安全的调用在大多数现代环境中已被弃用。

      【讨论】:

      • 微软的一次性的、不完全符合标准的、不可移植的可选附件 K 函数 fopen_s() 的实现的可移植替代方案是 C 标准函数fopen().
      【解决方案7】:

      如果您希望它在许多平台上使用,您可以按照评论使用定义如下:

      #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) &amp;&amp; (_MSC_VER &gt;= 1600) ) ... #ELSE ... 怎么样?应该涵盖所有情况吧?
      • _MSC_VER = 1600 可能不是第一个弃用 fopen() 等的版本。这是我遇到问题的第一个版本。
      • 看起来带有(部分)安全功能的 MSVC 的第一个版本是 2005 年,_MSC_VER = 1400。
      【解决方案8】:

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

      #define _CRT_SECURE_NO_WARNINGS
      

      然后它会编译。

      【讨论】:

      • 这似乎对我不起作用。仍然会出现 freopen 的编译错误。
      • @LeviRoberts 你必须把这个定义放在文件的最顶部,包含一些头文件时会产生错误
      【解决方案9】:

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

      但是,我与这个问题斗争了几年。我发布了一组更大的转换宏here.,对于您的直接问题,将以下代码放入包含文件中,并将其包含在您的源代码中:

      #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
      

      当然,这种方法并没有实现预期的异常行为。

      【讨论】:

      • MS _s 通常与 C11 边界检查接口不同。有些具有相同的特性,有些则没有。由于该接口是可选的,因此很少有实现支持它,因为它大多是不必要的。而且您的代码是 C++,而不是您在文本中引用的 C。
      • @Olaf:嗯。除了指出我的异常行为警告之外,我无法解决边界检查问题。
      • 你说得对,我引用了 C11 标准(而不是 C++14 或 17)。这些函数在 Microsoft 的 C++ 编译器的最新版本中可用。事实证明,附件 K 在 MSVS 之外并未得到广泛支持。 Jonathan Leffler 评论说here MS 版本实际上与附件 K 规范不匹配。便携性非常重要。
      • 如果您完整地阅读我的 cmets,我将不胜感激。 MSVC 并没有真正使用 BCI,而是他们自己的汤。 MSVC 至少 18 年以来一直不合规,并且非常清楚不打算这样做,至少包括像 VLA 这样的 C99 强制性功能,多年来每个现代编译器都支持这些功能(包括主要的嵌入式)。
      • 提问者标记为 Visual C++。我从一个较大的 C++ 文件中复制了代码。对于 C,我猜想包含的内容是 stdio.hstring.h (不过,上面的代码中没有使用字符串)。我不需要 using namespace std; 语句——这在 C 中有效吗?我在想 inline extern ... 应该是 C 中的 static inline 以避免链接器问题。这些天我写的C代码不多。如果我错了,请添加评论。
      【解决方案10】:

      我也遇到了同样的问题。当我尝试添加 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++ -> 预编译头文件 -> 选择在预编译头文件中不使用预编译头文件。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-12-04
        • 1970-01-01
        • 1970-01-01
        • 2013-09-11
        • 2021-07-12
        相关资源
        最近更新 更多