【C/C++】时间精确到微秒、纳秒
在之前的文章【C/C++】日常时间的获取、格式化等操作汇总中讲到的时间都是以秒为精度的。有时候需要确定某个事件的准确时间,就得把精度提高到毫秒(millsecond)、微秒(microsecond)、纳秒(nanosecond,很少用)。这里将讲解并演示如何使用。
C语言中所支持的精度在秒之下有微秒和纳秒,所以需要精度为毫秒的话建议直接使用微秒这个更高精度的时间值。
文章结构:
高精度时间结构体
- 微秒
在结构体中,#include <sys/time.h> struct timeval { time_t tv_sec; /* seconds */ suseconds_t tv_usec; /* microseconds */ };
tv_sec
表示当时时刻的秒数,和之前文章提到的日常时间或时间绝对值是等价的。tv_usec
则是微秒值。即1000000微秒为1秒,所以其取值范围为[0, 1000000)。
由于tv_sec
的time_t
的结构体,所以很容易获取当前时间的详情或格式化成时间文本。见之前的文章【C/C++】日常时间的获取、格式化等操作汇总。
- 纳秒
#include <time.h> struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ };
在结构体中,tv_sec
也表示当时时刻的秒数。tv_nsec
则是纳秒值。即10亿纳秒为1秒,所以其取值范围为[0, 10^12)。
时间函数
- 获取微秒:
int gettimeofday(struct timeval *tv, struct timezone *tz);
执行本函数后,所获取的时间值将会被存储在第一个参数tv
中,第二参数tz
在Linux中已经不被使用了(自己搜索夏令时
),所以直接传NULL
。
函数正常执行后将会返回0,否则返回-1并可通过errno来查看失败原因。
如果系统管理员修改了机器的时间(调整日期),则本函数所获取的时间也会随之发生变化。
- 获取纳秒:
获取纳秒的步骤比较麻烦,需要提前获取进程id,和clock_id
。
获取进程id的函数如下:
#include <unistd.h>
pid_t getpid(void);
pid_t getppid(void);
getpid()
返回当前进程的进程id,getppid()
返回当前进程的父进程的进程id。
#include <time.h>
int clock_getcpuclockid(pid_t pid, clockid_t *clock_id);
获取指定进程的clock_id
。如果参数pid
赋值为0,则获取的是当前函数执行的进程的clock_id
。
当函数正常执行时返回0,且clock_id
会被正确赋值;出错时则返回ENOSYS
(内核版本不支持)、EPERM
(权限不够)、ESRCH
(找不到id值为pid的进程)。
#include <time.h>
int clock_gettime(clockid_t clk_id, struct timespec *tp);
这才是最后的最后,获取纳秒。
与gettimeofday()
不同的是clock_gettime()
是获取进程的时间所经过的时间,所以不随系统管理员修改机器时间而改变。
一般用不到纳秒,本文章不预继续讨论了。(我会跟你说其实是我懒得写了! (逃… )
宏:计算时间差
获取到微秒的时间后,由于时间被分开成了两个值来表示,所以时间差的计算并不能直接相减。
查看time.h
发现已经有一些现成长定义好的宏可以用来计算时间差
1 | #define timersub(tvp, uvp, vvp) \ |
被减数tvp
减去 uvp
的结果存储于vvp
中。
还有一些其它的宏,如:
1 | timerclear // 清除时间 |
示例代码
以下代码演示获取微秒时间 ,并转换为日常时间的格式化字符串,最后求得本段代码在运行时的总耗时。
1 | struct timeval t_val; |
运行结果: