gettimeofday() - 为什么同时使用秒和微秒?

gettimeofday() - Why use both seconds and microseconds?

我需要将函数 gettimeofday 用于家庭作业,在阅读手册页和一些在线示例后,我不明白为什么人们有时会同时使用结构的 tv_sec 成员和tv_usec 结构成员。 手册页指出:

  The tv argument is a struct timeval (as specified in <sys/time.h>):

       struct timeval {
           time_t      tv_sec;     /* seconds */
           suseconds_t tv_usec;    /* microseconds */
       };

因此,假设我需要 return 以纳秒为单位的时间,并且我创建了两个时间间隔结构,开始和结束,并且我使用 gettimeofday() 记录了它们的时间。 当然,我的第一个想法是计算微秒的差异,即 start.tv_usec-end.tv_usec 然后乘以 1000 将其转换为纳秒。

但是网上很多例子和教程都是计算秒和微秒的差值,然后换算然后相加。 (e.g.)

我通读了整个手册页,但找不到原因,如果有任何解释,我将不胜感激。

"microseconds" 字段没有足够的 space 来存储过去的所有时间。 "seconds" 字段不够精确。它们一起提供的信息最多。

时间由秒数加上 0 - 999999 范围内的微秒数表示。

tv_sec 保存自 Unix 纪元 — 1970-01-01 00:00:00 +00:00 — 和 tv_usec(或 tv_nsec 在使用更现代的 struct timespec) 时保留小数部分 — struct timeval 的值为 [0..999,999] 微秒,struct timespec.[=43 的值为 [0..999,999,999] 纳秒=]

在 64 位整数普及之前,time_t 是 32 位有符号类型,而 'runs out' 在 2038 年 1 月——自从时代。在单个整数中没有存储亚秒单位的空间。

-2147483647 = 1901-12-13 20:45:53 +00:00
+2147483647 = 2038-01-19 03:14:07 +00:00

即使现在,如果处理纳秒,您也需要 30 位来表示最多 999,999,999 纳秒(以及 20 位来表示最多 999,999 微秒)。纳秒的要求意味着尝试缩放 64 位数字来表示秒和纳秒是不明智的——Y2K38 问题将被推迟大约 280 年,而两部分解决方案将它推迟到宇宙结束之后,这对每个人来说应该足够长了。 (我计划在 5000-01-02 开始处理 Y10K 问题,如果我还在的话。)

因此,虽然不理想,但两部分结构使得使用带有 time_t 值的常规格式化函数变得容易 — 它们有很多,而那些带有 struct tm 来自 time_t 值。而且它们的算术并不难。

我注意到,在某些方面,struct timevalstruct timespec 都未被 POSIX 指定。如果 tv_sec 分量为负,struct timevalstruct timespectv_usectv_nsec 部分的符号是什么(参见 Seconds Since the Epoch如果年份<1970或值为负数,则关系未定义)。 POSIX 未定义 tv_sec 的负值行为,这可能是明智的,但确实让生活有点困难。当然,还有"when did which part of which country switch between the Julian and Gregorian calendars?"和"was there a year zero?"的问题也是需要处理的。当 time_t 是一个 32 位数字时,它可以追溯到 1901 年 12 月,这在很大程度上避免了这些问题(但俄罗斯直到十月革命之后才从 Julian 转换为 Gregorian,十月革命发生在 11 月公历)。现在 time_t 通常是一个 64 位数字,BC(或 BCE)年也可以表示。

打印 tv_usectv_nsec 部分时要小心。请记住通过使用 %.6d 微秒,%.9ld 纳秒来添加足够的前导零,其中必要的转换说明符(d vs ld vs …)用于 tv_usec is not clearly defined in POSIX — but d is usually correct. (The tv_nsec会员是long;这既简单又可靠。)