C++ - 'localtime' 函数或变量可能不安全

16

我正在为学习目的编写一个简单的C++日志类。我的代码包含一个返回当天日期字符串的函数。但是,每当调用“localtime”函数时,我都会收到编译器错误。

std::string get_date_string(time_t *time) {
    struct tm *now = localtime(time);
    std::string date = std::to_string(now->tm_mday) + std::to_string(now->tm_mon) + std::to_string(now->tm_year);
    return date;
}

我尝试使用#define _CRT_SECURE_NO_WARNINGS,但它没有起作用,相同的错误出现了。我还尝试将_CRT_SECURE_NO_WARNINGS放在项目属性中的预处理器定义中。这导致了一个未解决的外部错误。

有人有什么想法吗?


1
确切的警告信息在哪里?使用localtime可能是危险的,因为它返回一个指向它拥有的内存区域的指针,所以如果你多次调用它,你需要确保每次都复制结构体。另外,顺便说一下,如果你得到了"2112016"这样的字符串,你不知道它是21/1/2016还是2/11/2016。 - Klitos Kyriacou
1
不要使用此函数,因为警告中给出的原因。 - Ben
3个回答

62
问题在于std::localtime不是线程安全的,因为它使用了静态缓冲区(在线程之间共享)。POSIXWindows都有安全的替代方法:localtime_rlocaltime_s
这是我所做的:
inline std::tm localtime_xp(std::time_t timer)
{
    std::tm bt {};
#if defined(__unix__)
    localtime_r(&timer, &bt);
#elif defined(_MSC_VER)
    localtime_s(&bt, &timer);
#else
    static std::mutex mtx;
    std::lock_guard<std::mutex> lock(mtx);
    bt = *std::localtime(&timer);
#endif
    return bt;
}

// default = "YYYY-MM-DD HH:MM:SS"
inline std::string time_stamp(const std::string& fmt = "%F %T")
{
    auto bt = localtime_xp(std::time(0));
    char buf[64];
    return {buf, std::strftime(buf, sizeof(buf), fmt.c_str(), &bt)};
}

5
比被选中的答案更好的回答 - elven_inside

2
使用C++20的chrono库更新答案
    const auto now            = std::chrono::system_clock::now();
    const auto time_zone      = std::chrono::current_zone();
    const auto local_time     = time_zone->to_local(now);
    const auto time_point     = std::chrono::time_point_cast<std::chrono::days>(local_time);
    const auto year_month_day = std::chrono::year_month_day{ time_point };

    int year  = static_cast<int>(year_month_day.year());
    int month = static_cast<unsigned>(year_month_day.month());
    int day   = static_cast<unsigned>(year_month_day.day());

这将提供当前的UTC日期。您可以通过首先将system_clock::now()转换为local_time,然后使用current_zone()->to_local()来获取当前的本地日期。 - Howard Hinnant
@HowardHinnant,已更新,感谢您的评论。 - why stuff works

-2

在包含任何其他头文件之前,尝试使用以下代码定义#define _CRT_SECURE_NO_WARNINGS

#define _CRT_SECURE_NO_WARNINGS
#include <ctime>
//your code

27
不要这样做。相反认真对待CRT安全警告! - Ben

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接