本地时间与本地时间_s以及适当的输入参数

55
time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime ( &rawtime );

这里返回警告C4996:“localtime”:此函数或变量可能不安全。考虑改用localtime_s。

time_t rawtime;
struct tm * timeinfo;
time ( &rawtime );
timeinfo = localtime_s ( &rawtime );

当我将localtime更改为localtime_s时,我收到以下错误:error C2660:'localtime_s':函数不接受1个参数

以下是我认为在第一个代码块中正在发生的事情:

  • 创建一个空的time_t变量。
  • 创建指向定义在ctime中的timeinfo的指针
  • 将rawtime写入rawtime引用
  • 将rawtime转换为对行人有意义的内容

    1. 我是对的吗?
    2. localtime_s需要什么第二个输入参数?
    3. 如果我忽略整个localtime安全问题,最糟糕的情况会是什么。

1. 对的。


2. localtime_s需要一个指向struct tm 的指针作为第二个输入参数。


3. 如果忽略localtime的安全问题,可能会遇到缓冲区溢出和其他安全问题。


1
是的,我立刻找到了这个链接:http://msdn.microsoft.com/en-us/library/a442x3ye(v=vs.80).aspx 但是我还不理解如何解释这些模板/通用的方法描述。就像我不理解一般形式维基数学文章的语法/符号一样。 对于我实际告诉该方法的内容,struct tm* _tm和const time_t *time对我来说毫无意义...尽管我希望它有意义。 - ProGirlXOXO
是的,我也有一些这样的。 - ProGirlXOXO
3个回答

69

localtime 返回一个指向静态分配的 struct tm 的指针。

使用 localtime_s,您需要传递一个指向 struct tm 的指针,localtime_s 将其结果数据写入其中,因此您的代码将从以下代码更改:

struct tm *timeinfo;
timeinfo = localtime(&rawtime);

变成这样:

struct tm timeinfo;
localtime_s(&timeinfo, &rawtime);

这种方式会将内容写入你的缓冲区,而不是使用自己的缓冲区。


通过这些更改,我得到了以下错误:错误C2679:找不到接受右操作数类型为'errno_t'的二进制“=”运算符(或者没有可接受的转换) 1> c:\Program Files\Microsoft Visual Studio 10.0\VC\include\wchar.h(1120):可能是'tm&tm::operator =(const tm&)',尝试匹配参数列表'(tm, errno_t)' 错误C2664:'strftime':无法将参数4从'tm'转换为'const tm *' 1> 没有可用于执行此转换的用户定义的转换运算符,或者无法调用该运算符。 - ProGirlXOXO
1
@ProGirlXOXO:这显然发生在你没有展示的代码中,但很可能是因为 timeinfo 现在是一个 struct tm 而不是指针,所以在其他函数使用它时,你需要将 timeinfo 更改为 &timeinfo - Jerry Coffin
这行代码:&timeinfo = localtime_s(&timeinfo, &rawtime); 报错如下:error C2440: '=' : 无法从 'errno_t' 转换为 'tm *'。 - ProGirlXOXO
5
请再仔细阅读答案。localtime函数返回一个指向struct tm结构体的指针,而localtime_s函数则不是这样(它返回一个错误号来告诉您所请求的转换是否成功)。请注意不要改变原意并使翻译更加易懂。 - Jerry Coffin

8
localtime_s只是微软实现的本地时间函数,你可以继续使用localtime,因为它符合C++ ISO标准,只有微软将其标记为“已弃用”。在C++世界中,localtime函数本身并没有被废弃。 localtime_s参考文档表明应向其传递以下参数:
_tm 
Pointer to the time structure to be filled in.
 time 
Pointer to the stored time.

13
值得一提的是,POSIX标准纠正函数是localtime_r。该函数的功能完全相同,只是两个参数的顺序相反。 - Ben Voigt
localtime_s 是自 C11 标准以来的一部分,详情请参见 https://en.cppreference.com/w/c/chrono/localtime。 - Pietro
1
@Pietro 仅作为可选的附录K的一部分,该附录实际上只被微软(糟糕地)实现。根据使用附录K - 边界检查接口的领域经验:“由于与规范的众多偏差,微软的实现不能被认为是符合或可移植的。” - Andrew Henle
@AndrewHenle - 感谢您指出这一点。刚刚在cppreference上读到:“Microsoft CRT中的localtime_s实现与C标准不兼容,因为它具有相反的参数顺序。” - Pietro

8
正如Lightness Races in Orbit所指出的,localtime和其他一些时间函数一样,不是线程安全的。我想更深入地了解这个问题,于是我找到了一篇相关的博客文章,其中详细解释了这个问题。
下面的引用解释了为什么localtime不是线程安全的:

[...] localtime返回一个静态缓冲区(std::tm*)的指针。另一个线程可以调用该函数,并且在第一个线程完成读取std::tm*结构体内容之前,静态缓冲区可能已被覆盖。


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