【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; | 
运行结果:
