Yup, it's one of those things that often get overlooked.
(Just like read() and write() returning a short count, or -1 with errno == EINTR if a signal is delivered to a handler installed without SA_RESTART flag. We really, really need better POSIX C learning materials, concentrating on POSIX stuff like getline() instead of fgets(); nftw() or scandir() or glob() instead of opendir()/readdir()/closedir(), and so on. :rant:)
Whenever using clock_gettime(), the following utility functions come in handy:
static inline double difftimespec(const struct timespec after, const struct timespec before)
{
return (double)(after.tv_sec - before.tv_sec)
+ (double)(after.tv_nsec - before.tv_nsec) / 1000000000.0;
}
static inline int64_t difftimespec_ns(const struct timespec after, const struct timespec before)
{
return (int64_t)(after.tv_sec - before.tv_sec) * (int64_t)1000000000
+ (int64_t)(after.tv_nsec - before.tv_nsec);
}
static inline int64_t difftimespec_us(const struct timespec after, const struct timespec before)
{
return (int64_t)(after.tv_sec - before.tv_sec) * (int64_t)1000000
+ (int64_t)(after.tv_nsec - before.tv_nsec) / 1000;
}
static inline int64_t difftimespec_ms(const struct timespec after, const struct timespec before)
{
return (int64_t)(after.tv_sec - before.tv_sec) * (int64_t)1000
+ (int64_t)(after.tv_nsec - before.tv_nsec) / 1000000;
}
The first one is equivalent of standard C difftime() but for struct timespecs, the three others provide the difference in nanoseconds, microseconds, and milliseconds (rounding toward zero). The casts are very deliberate: if the time_t type is signed and wraps around, the result will be correct, using these casts. (This is true on all POSIXy systems I know of.) The nanosecond resolution works for intervals up to slightly over 292 years, the microsecond version slightly over 292,000 years, and the millisecond version slightly over 292,000,000 years, positive or negative.
The double version is nanosecond-precise for up to 104 day intervals; microsecond-precise for 285 years; and millisecond-precise for almost 285421 years. The order of the casting ensures that even when .tv_sec's are large, there will be no cancellation error, as only the difference is converted to floating-point and not the times themselves.
Of course, the clocks themselves do not necessarily increment every nanosecond; one needs to use clock_getres() to find out the resolution of a particular clock.