定时器环绕,灵活的位大小

时间:2015-08-05 07:47:50

标签: c timer bit-manipulation integer-overflow

给定计数器/计时器增加并简单地包裹在给定的位宽度,这是一个众所周知的解决方案,可以找到计数器的两个捕获值之间的差异(计数器可能包含在两个点之间)只是在计数器上执行无符号减法(如果不知道哪一个更大,可能会将结果解释为已签名)。

例如,如果给定一个32位定时器,可以使用这样的代码来确定某些代码运行所需的时间长度:

uint32_t start = GetSomePlatformSpecificTimer();
RunSomeOtherCode();
uint32_t end = GetSomePlatformSpecificTimer();
uint32_t platformTicksTakenByCode = end - start;

或者检查是否已达到某个时间限制:

uint32_t limit = GetSomePlatformSpecificTimer() + timeLimitInTicks;
while (true)
{
    bool finished = DoSomethingSmall();
    if (finished)
        break;
    if ((int32_t)(GetSomePlatformSpecificTimer() - limit) >= 0)
        return ERROR_TIMEOUT;
}

如果已知定时器为32位宽,则效果很好。它还可以通过更改使用的类型来调整16位或8位定时器。

在计时器大小与类型大小不匹配的情况下,是否有类似的简单方法可以做同样的事情?例如,24位定时器或18位定时器。

假设位大小<= 32且在某些外部标头中由#define COUNTER_WIDTH指定(并且可能会更改)。

是将两个计数器值从COUNTER_WIDTH签名扩展到32位的最佳解决方案,然后使用上面的代码吗?我可以看到可能为FF工作 - &gt; 00翻转,但我认为它会打破7F - &gt; 80翻转,所以可能必须对此进行某种检查(如果值接近零则可能是符号扩展,如果值接近中点则可以是零扩展)。我认为这也意味着两个值之间的差异不应超过计数器范围的四分之一,否则可能会导致问题。

或者有更好的方法吗?

1 个答案:

答案 0 :(得分:0)

而不是符号扩展,您可以相乘,以便整个范围变为与算术类型相同的大小。换句话说,使用定点算术来填充整数。在您的情况下,使用uint32_t,看起来像

uint32_t start = GetSomePlatformSpecificTimer();
RunSomeOtherCode();
uint32_t end = GetSomePlatformSpecificTimer();
start <<= 32-COUNTER_WIDTH;
end <<= 32-COUNTER_WIDTH;
uint32_t platformTicksTakenByCode = end - start;
platformTicksTakenByCode >>= 32-COUNTER_WIDTH;

显然你想要封装那个算术:

const uint32_t start = GetScaledTimer();
RunSomeOtherCode();
const uint32_t end = GetScaledTimer();
const uint32_t platformTicksTakenByCode = RescaleDuration(end - start);

uint32_t GetScaledTimer()
{
    return GetSomePlatformSpecificTimer() << 32-COUNTER_WIDTH;
}
uint32_t RescaleDuration(uint32_t d)
{
    return d >> 32-COUNTER_WIDTH;
}

然后,您的行为与全宽度计时器的行为大致相同,并且必要时使用签名类型的相同选项。