错误 C4996:“ctime”:此函数或变量可能不安全
Posted
技术标签:
【中文标题】错误 C4996:“ctime”:此函数或变量可能不安全【英文标题】:error C4996: 'ctime': This function or variable may be unsafe 【发布时间】:2012-11-13 02:30:14 【问题描述】:我有一个关于静态源代码分析的大项目,一切都编译成功,除了一件事。我在标题中提供了错误消息。让我感到困惑的是,它给出了一条错误消息,说不安全。我认为这应该只是警告,而不是错误。顺便说一句,我使用的是 Visual Studio 2012。这是我在 ctime 中收到错误的代码部分。如果有人可以帮助我克服这个错误,我会很高兴。
void CppCheckExecutor::reportProgress(const std::string &filename, const char stage[], const std::size_t value)
(void)filename;
if (!time1)
return;
// Report progress messages every 10 seconds
const std::time_t time2 = std::time(NULL);
if (time2 >= (time1 + 10))
time1 = time2;
// current time in the format "Www Mmm dd hh:mm:ss yyyy"
const std::string str(std::ctime(&time2));
// format a progress message
std::ostringstream ostr;
ostr << "progress: "
<< stage
<< ' ' << value << '%';
if (_settings->_verbose)
ostr << " time=" << str.substr(11, 8);
// Report progress message
reportOut(ostr.str());
【问题讨论】:
【参考方案1】:如果您查看ctime 的描述,您会注意到:
此函数返回指向静态数据的指针,并且不是线程安全的。此外,它还修改了静态tm 对象,可以与gmtime 和localtime 共享。 POSIX 将此函数标记为已过时,并推荐使用 strftime。
行为可能未定义,因为 time_t 的值导致字符串长度超过 25 个字符(例如 10000 年)
...有很多事情需要担心。
另一方面,如果你看看strftime:
size_t strftime(char* str, size_t count, const char* format, tm* time);
返回值
写入 str 指向的字符数组的字节数,不包括成功时的终止 '\0'。如果在可以存储整个字符串之前达到计数,则返回0并且内容未定义。
所有参数都是显式的,因此您可以完全控制可能的数据竞争,并且也不存在溢出缓冲区的风险。
虽然这是 C 方式,但 C++ 引入了 <chrono>
,其中特定函数 std::put_time
也可用于将时间输出到流:
#include <iostream>
#include <iomanip>
#include <ctime>
#include <chrono>
int main()
std::time_t const now_c = std::time();
std::cout << "One day ago, the time was "
<< std::put_time(std::localtime(&now_c), "%F %T") << '\n';
这样更好,因为您不再需要担心可能的缓冲区溢出。
【讨论】:
感谢 chrono 和 put_time! 请注意,std::localtime
还返回一个指向静态数据的指针,并且可能不是线程安全的,因此这只能修复可能的缓冲区溢出。
@interjay: 对,C++ 示例只涉及打印部分;不幸的是,我不知道从 time_t
到 struct tm
的转换函数既是标准的又是线程安全的。
对于 VS 2017 的构造函数有所改变:std::time_t const now_c = std::time(NULL);【参考方案2】:
如果您确定您的代码中没有安全问题,您可以通过#pragma warning(disable : 4996)
禁用此功能。
【讨论】:
【参考方案3】:是的,它应该只是警告,而不是错误。 要获得简单的警告而不是错误,请在 VS 项目中禁用 SDL 检查(在配置属性 -> C/C++ -> 常规选项卡中)。
【讨论】:
根据en.cppreference.com/w/c/chrono/ctime,此功能已过时。 POSIX 和 C 标准推荐使用strftime
。【参考方案4】:
std::ctime
不是线程安全的,原因有两个:
std::tm
类型的全局对象。
它修改一个全局char
数组并返回一个指向该数组的指针。
如果您有其他线程调用 std::gmtime
、std::localtime
或 std::ctime
,则可能会发生冲突。
最好的办法是将对std::ctime
的调用转换为对std::strftime
的调用。这与 POSIX 一致,后者认为 ctime
已过时并建议使用 strftime
代替。
【讨论】:
【参考方案5】:与 2017 年相比:
#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include <ctime>
#include <chrono>
int main()
std::time_t const now_c = std::time(NULL);
auto s = std::put_time(std::localtime(&now_c), "%F %T");
std::cout << s << std::endl;
但无论如何你都会收到:
....cpp(31): 警告 C4996: 'localtime': 此函数或变量可能不安全。考虑改用 localtime_s。要禁用弃用,请使用 _CRT_SECURE_NO_WARNINGS。有关详细信息,请参阅在线帮助。
为了防止你可以使用:
errno_t err;
struct tm time_info;
time_t time_create = time(NULL);
localtime_s(&time_info, &time_create);
char timebuf[26];
err = asctime_s(timebuf, 26, &time_info);
plain C 部分取自 MSDN...旧方式..
【讨论】:
以上是关于错误 C4996:“ctime”:此函数或变量可能不安全的主要内容,如果未能解决你的问题,请参考以下文章
windows系统下VS2013或者VS2017的C4996错误解决方法
Visual Studio错误:strcpy出现C4996错误的解决
localtime vs localtime_s 和适当的输入参数
vs2013/2015中scanf函数类似于error C4996: 'scanf': This function or variable may be unsafe的安全检查错误