只要满足以下两点,就不会出错:
先减去 DWORD
后,再进行其他类型的转换。
计时的时间不超过 49.7 天。
这是因为在 C 语言中,无符号算术溢出是有明确定义的,并且包装行为恰好符合我们的需求。
DWORD t1, t2;
DWORD difference;
t1 = GetTickCount();
DoSomethingTimeConsuming();
t2 = GetTickCount();
t2 - t1
会产生正确的值,即使
GetTickCount
发生了包裹。但在执行减法之前不要将
t2
和
t1
转换为其他类型(例如
int
或
double
)。
如果程序语言将溢出视为错误,则此方法无效。如果
DoSomethingTimeConsuming()
所需时间超过49.7天,则此方法也无效。遗憾的是,仅凭
t2
和
t1
看不出
GetTickCount
包裹了多少次。
让我们从通常情况开始,其中没有包裹发生:
t1 = 13487231
t2 = 13492843
这里,t2 - t1 = 5612
,意味着该操作花费了约五秒钟。
现在考虑一个耗时较短的操作,但其中GetTickCount
已经绕过了一圈:
t1 = 4294967173
t2 = 1111
操作耗时1234ms,但计时器已经循环了,
1111-4294967173
是虚假值
-4294966062
。我们该怎么办呢?
好吧,在模2的32次方下,减法的结果也会循环:
(DWORD)-4294966062 == (DWORD)1234
最后,考虑一种极端情况,即操作所需时间接近于 232 毫秒,但并非完全相等:
t1 = 2339189280
t2 = 2339167207
在这里,GetTickCount
被包裹起来,然后又回到了原来的位置。
现在 t2 - t1
给出了一个看起来很假的值,4294945223
。这是因为那就是操作实际花费的时间!
一般而言:
(base + offset) - base ≡ offset mod 2^32