如何以" Safe "的方式获取 C++ 中的当前时间

How to get the current time in c++ in a " Safe " way

本文关键字:时间 C++ 方式 Safe 获取      更新时间:2023-10-16

我对C++并不陌生,但我大多只使用最基本的标准库功能,如<iostream><vector><map>等。

现在,我正在开发一个简单的游戏,我正在研究一个记录器类,但我坚持获取当前时间。

不要误会我的意思,我已经看到了很多方法可以在StackOverflow和Google中获取时间,但根据Visual Studio的说法,它们都不是"安全的"。 例如,当我使用asctime()ctime()时,我收到此错误:

['ctime':此函数或变量可能不安全。请考虑改用ctime_s。要禁用弃用,请使用_CRT_SECURE_NO_WARNINGS。有关详细信息,请参阅联机帮助]。

但是当我尝试以好的方式做到这一点并使用安全版本时,我发现它们更加复杂,例如这是ctime()函数:

ctime(const time_t *const_time)

ctime_s()相比:

ctime_s(char *const _Buffer, const size_t _SizeinBytes,const time_t *const _Time)

再次在互联网上查找对我没有帮助,所以我在这里,询问你们如何获取当前时间,我的意思是使用"安全"方法10:20或类似的东西。

Modern C++ 具有用于时间提取和操作目的的<chrono>标头,一旦你理解了它,它就比传统的 C 东西好得多

#include <iostream>
#include <chrono>
#include <ctime>
int main() {
auto start = std::chrono::system_clock::now();
auto legacyStart = std::chrono::system_clock::to_time_t(start);
std::cout << std::ctime(&legacyStart) << 'n';
}

这可以通过多种方式使用,包括(如图所示(输出日期的字符串表示形式。我意识到对于这个简单的案例来说,这不是必需的,但如果你不想被称为 C+ 编码员(a(,建议您搬到<chrono>

如果您可以使用 C++20,则尤其如此,因为该迭代包括日历功能(用于日期(和时间功能(用于将自午夜以来的持续时间拆分为小时、分钟和秒等单个组件(。

如果你可以开始使用它们,你将永远不再需要传统的C东西:-(


关于这是否不安全,我认为Microsoft经常对编码人员做出这个决定造成伤害。我实际上关闭了这些警告,因为我知道所涉及的风险,并且知道如何避免问题。

无论如何,我相信我在某个时候读到s是为了安全而不是安全,因为例如,如果您将错误的长度传递给它们,某些替换功能是不安全的:

char dest[10];
strcpy_s(dest, 100, "13 characters");

毫无疑问,有些人会说这是编码人员的错,因为他们应该知道自己在做什么,但对于所谓的不安全功能,也可以提出同样的论点。

ctime()的具体问题是允许它返回内部缓冲区的地址,该地址可能会在下次调用时被覆盖(这也可能包括在您完成之前调用它的另一个线程(。

如果您知道自己的使用模式(包括您使用的任何第三方内容(,则可以轻松使用ctime()而不会出现问题。

但是,在这种情况下,使用更安全的变体并不难

,例如:
#include <iostream>
#include <chrono>
#include <ctime>
int main() {
auto start = std::chrono::system_clock::now();
auto legacyStart = std::chrono::system_clock::to_time_t(start);
char tmBuff[30];
ctime_s(tmBuff, sizeof(tmBuff), &legacyStart);
std::cout << tmBuff << 'n';
}

尽管您可能需要考虑使用strftime以便更好地控制输出格式(例如"yyyy-mm-dd hh:mm:ss"(,从而保证生成的字符串适合缓冲区(。


(a(那个奇怪的品种,从来没有完全从C过渡到C++:-(

asctime()ctime()函数是"不安全的",因为它们返回指向静态缓冲区的指针,这些缓冲区可能是线程安全的,也可能不是线程安全的,具体取决于实现,如果它们不是线程安全的,那么它们可能会在您有机会使用它们之前被其他线程覆盖。

"更安全"的asctime_s()ctime_s()函数写入您必须提供的预分配缓冲区,例如:

time_t now = time(NULL);
//char *str = asctime(localtime(&now));
tm now_tm = {};
char str[26] = {};
localtime_s(&now_tm, &now);
asctime_s(str, 26, &now_tm);
// use str as needed...
time_t now = time(NULL);
//char *str = ctime(&now);
char str[26] = {};
ctime_s(str, 26, &now);
// use str as needed...