timeval 是 POSIX 定义的秒+微秒时间结构,std::chrono 不直接提供因其跨平台兼容性要求;Linux/macOS 用 gettimeofday() 最简可靠,Windows 需特殊换算,禁用 time() 等秒级接口。

timeval 是什么,为什么不能直接用 std::chrono
timeval 是 POSIX 定义的结构体,常用于 select()、settimeofday() 等系统调用,包含秒(tv_sec)和微秒(tv_usec)两个字段。C++ 标准库(如 std::chrono::system_clock::now())不直接提供 timeval,必须手动转换——这不是语法限制,而是跨平台兼容性要求:Windows 不原生支持 timeval,Linux/macOS 才有完整语义。
最简可靠写法:用 gettimeofday(Linux/macOS)
在类 Unix 系统上,gettimeofday() 是最直接、无时区转换开销的方式:
struct timeval tv; gettimeofday(&tv, nullptr); // tv.tv_sec 和 tv.tv_usec 已就绪
- 不需要
clock_gettime()再转,避免纳秒→微秒舍入误差 -
gettimeofday()已被标记为 legacy,但至今仍是获取timeval的事实标准,glibc 和 musl 都保证其精度与clock_gettime(CLOCK_REALTIME)一致 - 注意:第二个参数传
nullptr即可,传非空指针需分配struct timezone(已废弃,勿用)
跨平台 fallback:用 clock_gettime + 手动转
若需兼顾较新 Linux 或未来可移植性,可用 clock_gettime(),但必须小心处理单位转换:
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
struct timeval tv = {
.tv_sec = ts.tv_sec,
.tv_usec = static_cast<suseconds_t>(ts.tv_nsec / 1000)
};
-
ts.tv_nsec是纳秒,除以 1000 得微秒;直接截断(非四舍五入),因timeval.tv_usec范围是 [0, 999999],而ts.tv_nsec最大为 999999999 → 除后最大为 999999,安全 - Windows 上需用
GetSystemTimeAsFileTime()+ 11644473600LL 偏移换算,但结果仍是timeval语义;若项目不强制 Windows 支持,不建议增加该分支 - 别用
std::time(nullptr):它只给秒级,丢失全部微秒信息
常见错误:误用 time_t 或忽略符号问题
以下写法看似合理,实则危险:
立即学习“C++免费学习笔记(深入)”;
time_t now = time(nullptr);
struct timeval tv = { .tv_sec = now, .tv_usec = 0 }; // ❌ 错!丢失毫秒/微秒
-
time_t是秒级时间戳,无法还原 sub-second 部分 -
tv.tv_usec是suseconds_t(通常为long),若用int赋值可能在 32 位平台溢出(尽管实际不会,但类型不匹配) - 别对
tv.tv_usec做负数校正(如if (tv.tv_usec < 0) { ... }):所有正确 API 返回的tv_usec都在 [0, 999999] 区间内
真正需要小心的是跨平台构建时头文件是否包含完整定义:<sys/time.h> 必须在使用 timeval 或 gettimeofday() 前引入,否则编译失败或隐式声明警告。


















