您需要展示一些更有说服力的代码,并确定您遇到问题的平台。
例如:
#include <stdio.h>
#include <sys/time.h>
int main(void)
{
while (1)
{
struct timeval ts;
if (gettimeofday(&ts, 0) == 0 && ts.tv_usec >= 1000000)
printf("%lu s; %lu µs\n", (long)ts.tv_sec, (long)ts.tv_usec);
}
return 0;
}
非常繁忙的循环有点令人讨厌。也许您应该nanosleep()
在每次迭代中使用睡眠一两微秒:
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
int main(void)
{
while (1)
{
struct timeval tv;
if (gettimeofday(&tv, 0) == 0 && tv.tv_usec >= 1000000)
printf("%lu s; %lu µs\n", (long)tv.tv_sec, (long)tv.tv_usec);
struct timespec ts = { .tv_sec = 0, .tv_nsec = 2000 };
nanosleep(&ts, 0);
}
return 0;
}
或者,包括一个进度表来证明代码正在运行:
#include <stdio.h>
#include <sys/time.h>
#include <time.h>
int main(void)
{
size_t loop_count = 0;
size_t line_count = 0;
while (1)
{
struct timeval tv;
if (gettimeofday(&tv, 0) == 0 && tv.tv_usec >= 1000000)
printf("%lu s; %lu µs\n", (long)tv.tv_sec, (long)tv.tv_usec);
struct timespec ts = { .tv_sec = 0, .tv_nsec = 2000 };
nanosleep(&ts, 0);
if (++loop_count > 100000)
{
loop_count = 0;
putchar('.');
line_count++;
if (line_count >= 50)
{
putchar('\n');
line_count = 0;
}
fflush(stdout);
}
}
return 0;
}
timersub()
在 Ubuntu 16.04 LTS VM 上,我可以找到/usr/include/x86_64-linux-gnu/sys/time.h
包含宏的文件:
# define timersub(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
if ((result)->tv_usec < 0) { \
--(result)->tv_sec; \
(result)->tv_usec += 1000000; \
} \
} while (0)
我能看到的所有迹象都是tv_usec
一个__u32
,一个无符号的数量。 如果是这种情况,那么< 0
条件永远不会成立,您有时可能会看到异常大的正值。YMMV,当然。
连我的里程数都不一样
进一步的审查表明,虽然有些头文件似乎__u32
用于tv_usec
,但它们并不是主要的系统头文件。
/usr/include/linux/time.h: __kernel_suseconds_t tv_usec; /* microseconds */
/usr/include/linux/can/bcm.h: long tv_usec;
/usr/include/drm/exynos_drm.h: __u32 tv_usec;
/usr/include/drm/exynos_drm.h: __u32 tv_usec;
/usr/include/drm/vmwgfx_drm.h: uint32_t tv_usec;
/usr/include/drm/drm.h: __u32 tv_usec;
/usr/include/rpc/auth_des.h: uint32_t tv_usec; /* Microseconds. */
/usr/include/valgrind/vki/vki-darwin.h:#define vki_tv_usec tv_usec
/usr/include/valgrind/vki/vki-linux.h: vki_suseconds_t tv_usec; /* microseconds */
/usr/include/rpcsvc/rstat.x: unsigned int tv_usec; /* and microseconds */
/usr/include/rpcsvc/rstat.h: u_int tv_usec;
/usr/include/x86_64-linux-gnu/bits/utmpx.h: __int32_t tv_usec; /* Microseconds. */
/usr/include/x86_64-linux-gnu/bits/time.h: __suseconds_t tv_usec; /* Microseconds. */
/usr/include/x86_64-linux-gnu/bits/utmp.h: int32_t tv_usec; /* Microseconds. */
/usr/include/x86_64-linux-gnu/sys/time.h: (ts)->tv_nsec = (tv)->tv_usec * 1000; \
/usr/include/x86_64-linux-gnu/sys/time.h: (tv)->tv_usec = (ts)->tv_nsec / 1000; \
/usr/include/x86_64-linux-gnu/sys/time.h:# define timerisset(tvp) ((tvp)->tv_sec || (tvp)->tv_usec)
/usr/include/x86_64-linux-gnu/sys/time.h:# define timerclear(tvp) ((tvp)->tv_sec = (tvp)->tv_usec = 0)
/usr/include/x86_64-linux-gnu/sys/time.h: ((a)->tv_usec CMP (b)->tv_usec) : \
/usr/include/x86_64-linux-gnu/sys/time.h: (result)->tv_usec = (a)->tv_usec + (b)->tv_usec; \
/usr/include/x86_64-linux-gnu/sys/time.h: if ((result)->tv_usec >= 1000000) \
/usr/include/x86_64-linux-gnu/sys/time.h: (result)->tv_usec -= 1000000; \
/usr/include/x86_64-linux-gnu/sys/time.h: (result)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
/usr/include/x86_64-linux-gnu/sys/time.h: if ((result)->tv_usec < 0) { \
/usr/include/x86_64-linux-gnu/sys/time.h: (result)->tv_usec += 1000000; \
对于具有该名称的成员使用无符号类型的任何代码令人担忧,但这并不意味着使用struct timeval
and的代码会发生这种情况timersub()
。
这段代码:
#include <sys/time.h>
#include <stdio.h>
int main(void)
{
struct timeval t = { .tv_sec = 0, .tv_usec = -1 };
printf("%ld %ld\n", (long)t.tv_sec, (long)t.tv_usec);
return 0;
}
为 64 位编译(所以long
足够大,可以容纳任何tv_usec
可以定义为的内容)打印0 -1
。可以将tv_usec
成员初始化为0
,将其递减,并验证它是否为负,以及各种其他相关测试。
所以,问题并不像“timersub()
错了”那么简单——这是一种巨大的解脱。