下面是如何在 C++ 中获取简单的类似于 C 的毫秒、微秒和纳秒时间戳:
新的 C++11 std::chrono 库是我见过或试图弄清楚如何使用的最复杂的一堆 mess C++ 之一,但至少它是交叉的平台!
所以,如果你想简化它并使它更像“C”,包括删除它所做的所有类型安全类的东西,这里有 3 个简单且非常容易-使用函数获取以毫秒、微秒和纳秒为单位的时间戳...只花了我大约 12 小时来编写*:
注意:在下面的代码中,您可能会考虑使用std::chrono::steady_clock 而不是std::chrono::high_resolution_clock。他们从这里(https://en.cppreference.com/w/cpp/chrono)的定义如下:
- steady_clock (C++11) - 永远不会调整的单调时钟
- high_resolution_clock (C++11) - 具有最短滴答周期的时钟
#include <chrono>
// NB: ALL OF THESE 3 FUNCTIONS BELOW USE SIGNED VALUES INTERNALLY AND WILL
// EVENTUALLY OVERFLOW (AFTER 200+ YEARS OR SO), AFTER WHICH POINT THEY WILL
// HAVE *SIGNED OVERFLOW*, WHICH IS UNDEFINED BEHAVIOR (IE: A BUG) FOR C/C++.
// But...that's ok...this "bug" is designed into the C++11 specification, so
// whatever. Your machine won't run for 200 years anyway...
// Get time stamp in milliseconds.
uint64_t millis()
{
uint64_t ms = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count();
return ms;
}
// Get time stamp in microseconds.
uint64_t micros()
{
uint64_t us = std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count();
return us;
}
// Get time stamp in nanoseconds.
uint64_t nanos()
{
uint64_t ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count();
return ns;
}
* (抱歉,我更像是一个嵌入式开发人员而不是标准计算机程序员,所以所有这些高级的、抽象的 static-member-within-class-within-namespace-within-namespace-within-命名空间的东西让我很困惑。别担心,我会好起来的。)
问:为什么是std::chrono?
A:因为 C++ 程序员喜欢对事物发疯,所以他们让它为你处理单元。以下是一些 C++ 怪异和使用 std::chrono 的案例。参考本页:https://en.cppreference.com/w/cpp/chrono/duration。
因此,您可以声明一个 1 秒的变量并将其更改为微秒,而无需像这样进行强制转换:
// Create a time object of type `std::chrono::seconds` & initialize it to 1 sec
std::chrono::seconds time_sec(1);
// integer scale conversion with no precision loss: no cast
std::cout << std::chrono::microseconds(time_sec).count() << " microseconds\n";
你甚至可以像这样指定时间,在我看来,这非常奇怪而且太过分了。 C++14 从字面上重载了字符ms、us、ns 等作为函数调用运算符来初始化各种类型的std::chrono 对象,如下所示:
auto time_sec = 1s; // <== notice the 's' inside the code there
// to specify 's'econds!
// OR:
std::chrono::seconds time_sec = 1s;
// integer scale conversion with no precision loss: no cast
std::cout << std::chrono::microseconds(time_sec).count() << " microseconds\n";
Here are some more examples:
std::chrono::milliseconds time_ms = 1ms;
// OR:
auto time_ms = 1ms;
std::chrono::microseconds time_us = 1us;
// OR:
auto time_us = 1us;
std::chrono::nanoseconds time_ns = 1ns;
// OR:
auto time_ns = 1ns;
就我个人而言,我宁愿只是简化语言并这样做,就像我已经做的那样,就像在此之前几十年在 C 和 C++ 中所做的那样:
// Notice the `_sec` at the end of the variable name to remind me this
// variable has units of *seconds*!
uint64_t time_sec = 1;
这里有一些参考资料:
- 时钟类型 (https://en.cppreference.com/w/cpp/chrono):
system_clock
steady_clock
high_resolution_clock
utc_clock
tai_clock
gps_clock
file_clock
- 等
-
Getting an accurate execution time in C++ (micro seconds)(@OlivierLi 回答)
- http://en.cppreference.com/w/cpp/chrono/time_point/time_since_epoch
-
http://en.cppreference.com/w/cpp/chrono/duration - 显示小时、分钟、秒、毫秒等类型
- http://en.cppreference.com/w/cpp/chrono/system_clock/now
我还需要观看的视频:
- CppCon 2016: Howard Hinnant “A <chrono> Tutorial"
相关:
- 我的 3 组时间戳函数(相互交叉链接):
- 对于 C 时间戳,请在此处查看我的答案:Get a timestamp in C in microseconds?
- 对于 C++ 高分辨率时间戳,请在此处查看我的答案:Getting an accurate execution time in C++ (micro seconds)
- 对于 Python 高分辨率时间戳,请在此处查看我的答案:How can I get millisecond and microsecond-resolution timestamps in Python?
附录
operator"" mysuffix() 运算符重载/用户定义文字/后缀函数(从 C++11 开始)是上面奇怪的 auto time_ms = 1ms; 的工作原理。编写1ms 实际上是对函数operator"" ms() 的函数调用,将1 作为输入参数传入,就好像您编写了这样的函数调用:operator"" ms(1)。要了解有关此概念的更多信息,请参阅此处的参考页面:cppreference.com: User-defined literals (since C++11)。
这是定义用户定义文字/后缀函数并使用它的基本演示:
// 1. Define a function
// used as conversion from degrees (input param) to radians (returned output)
constexpr long double operator"" _deg(long double deg)
{
long double radians = deg * 3.14159265358979323846264L / 180;
return radians;
}
// 2. Use it
double x_rad = 90.0_deg;
为什么不直接使用类似double x_rad = degToRad(90.0); 的东西(就像几十年来在 C 和 C++ 中所做的那样)?我不知道。这与我猜想的 C++ 程序员的方式有关。也许他们正试图让现代 C++ 更加 Pythonic。
这个魔法也是可能非常有用的 C++ fmt 库的工作原理,这里是:https://github.com/fmtlib/fmt。它由Victor Zverovich 编写,也是C++20 的std::format 的作者。你可以看到函数detail::udl_formatter<char> operator"" _format(const char* s, size_t n)here的定义。它的用法是这样的:
"Hello {}"_format("World");
输出:
你好世界
这会将"World" 字符串插入{} 所在的第一个字符串中。这是另一个例子:
"I have {} eggs and {} chickens."_format(num_eggs, num_chickens);
示例输出:
我有 29 个鸡蛋和 42 只鸡。
这与 Python 中的str.format 字符串格式非常相似。阅读 fmt lib 文档here。