double timespec_delta2milliseconds(struct timespec *last, struct timespec *previous)
{
return (last->tv_sec - previous->tv_sec) (last->tv_nsec - previous->tv_nsec)*pow(10,-3);
}
This function computes the difference (last - previous) and returns the result expressed in milliseconds as a double. I tried a lot of different ways but if I don't do like this i receve in output segmentation fault. I think that this solution works but it's wrong, someone can help me ?
CodePudding user response:
The timespec
structure can handle fractions of a second, and the tv_nsec
is the fractions, represented as nanoseconds.
That means getting the difference between two timespec
structures isn't as straight-forward as you make it seem in your code.
Here's an example on how to get the difference, returned as a new timesepc
structure:
struct timespec diff_timespec(const struct timespec *time1, const struct timespec *time0)
{
struct timespec diff = {
.tv_sec = time1->tv_sec - time0->tv_sec,
.tv_nsec = time1->tv_nsec - time0->tv_nsec
};
if (diff.tv_nsec < 0)
{
diff.tv_nsec = 1000000000;
diff.tv_sec--;
}
return diff;
}
CodePudding user response:
You need two functions: sub_timespec()
, which calculates the difference between two time spec values, and timespec_as_milliseconds()
, which returns the number of milliseconds in a time spec value as an integer.
enum { NS_PER_SECOND = 1000000000 };
void sub_timespec(struct timespec t1, struct timespec t2, struct timespec *td)
{
td->tv_nsec = t2.tv_nsec - t1.tv_nsec;
td->tv_sec = t2.tv_sec - t1.tv_sec;
if (td->tv_sec > 0 && td->tv_nsec < 0)
{
td->tv_nsec = NS_PER_SECOND;
td->tv_sec--;
}
else if (td->tv_sec < 0 && td->tv_nsec > 0)
{
td->tv_nsec -= NS_PER_SECOND;
td->tv_sec ;
}
}
int64_t timespec_as_milliseconds(struct timespec ts)
{
int64_t rv = ts.tv_sec * 1000 ts.tv_nsec / 1000000;
return rv;
}
If you want to round the milliseconds, it gets trickier because you have to worry about carries and negative numbers and so on. You should not encounter a timespec value where the tv_sec
and tv_nsec
values have opposite signs (zeros aren't a problem).
In your code, adding pow(10, -3)
mixes floating point arithmetic with integer arithmetic — usually not a good idea.
If you want a double
value with up to 3 decimal places of fractional seconds, then you need:
double timespec_to_double_milliseconds(struct timespec ts)
{
double rv = ts.tv_sec (ts.tv_nsec / 1000000) / 1000.0;
return rv;
}
The first division is (deliberately) integer division; the second gives a floating-point value. Again, rounding has problems with carrying and so on.
Your function then becomes:
double timespec_delta2milliseconds(struct timespec *last, struct timespec *previous)
{
struct timespec delta = sub_timespec(*last, *previous);
return timespec_to_double_milliseconds(delta);
}
You can use an extra value in the function so it is easier to print the value returned in a debugger: double rv = timespec_to_double_milliseconds(delta); return rv;
.
The key idea, though, is to do separate tasks in separate functions. Taking the difference between two struct timespec
values is one task; converting a struct timespec
value to an appropriate double
is a separate task. When you can split things into separate tasks, you should.
I often pass struct timespec
values by value rather than pointer. The structure size is typically small enough that it is not a stress on the stack or registers. I return them by value too, which simplifies memory management — YMMV.
And, just in case it isn't clear, the tv_sec
member of a struct timespec
contains an integer number of seconds, and the tv_nsec
contains the fractional part of a second expressed as a number of nanoseconds (0 to 999,999,999). It requires care in printing the tv_nsec
value; you need a format such as %.9ld
to print 9 digits with leading zeros, and the type is long
. To print microseconds, divide the tv_nsec
value by 1,000 and change 9 to 6; to print milliseconds, divide by 1,000,000 and change 9 to 3. Beware negative values!