Delphi:如何避免EIntOverflow下溢?

编程入门 行业动态 更新时间:2024-10-11 17:29:38
本文介绍了Delphi:如何避免EIntOverflow下溢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述 微软已经在GetTickCount的文档中说过,你不能比较滴答计数,以检查间隔是否已经过去。例如:

不正确(伪代码):

code> DWORD endTime = GetTickCount + 10000; // 10 s from now ... if(GetTickCount> endTime) break;

上面的代码是坏的,因为它可以接受点击计数器的翻转。例如,假设时钟接近结束范围:

endTime = 0xfffffe00 + 10000 = 0x00002510 ; // 9,488 decimal

然后执行支票:

if(GetTickCount> endTime)

其中因为 GetTickCount c $ c> endTime :

if(0xfffffe01> 0x00002510)

解决方案

相反,您应该总是减去两个时间间隔:

DWORD startTime = GetTickCount; ... if(GetTickCount - startTime)> 10000 //如果是10秒 break;

查看相同的数学:

if(GetTickCount - startTime)> 10000 if(0xfffffe01 - 0xfffffe00)> 10000 如果(1> 10000)

很好的C / C ++,编译器以某种方式行事。

但是Delphi呢?

但是当我在Delphi中执行相同的数学计算时,会进行溢出检查( {Q +} , {$ OVERFLOWCHECKS ON} )当 TickCount 滚动时,减去两个滴答计数会产生EIntOverflow异常:

if (0x00000100 - 0xffffff00)> 10000 0x00000100 - 0xffffff00 = 0x00000200

这是什么意图解决方案问题?

编辑:我试图暂时关闭 OVERFLOWCHECKS :

{$ OVERFLOWCHECKS OFF}] delta = GetTickCount - startTime; {$ OVERFLOWCHECKS ON}

但减法仍然会抛出一个 EIntOverflow 异常

有没有更好的解决方案,涉及到转换和更大的中间变量类型?

更新

另一个我问的问题解释了为什么 {$ OVERFLOWCHECKS} code>不起作用它显然只适用于功能级别,而不是行级别。所以,以下不工作:

{$ OVERFLOWCHECKS OFF}] delta = GetTickCount - startTime; {$ OVERFLOWCHECKS ON}

以下 工作:

delta:= Subtract(GetTickCount,startTime); {$ OVERFLOWCHECKS OFF}] 函数Subtract(const B,A:DWORD):DWORD; begin 结果:=(B - A); 结束 {$ OVERFLOWCHECKS ON}

解决方案

一个这样一个简单的函数?

function GetElapsedTime(LastTick:Cardinal):Cardinal; var CurrentTick:Cardinal; begin CurrentTick:= GetTickCount; 如果CurrentTick> = LastTick然后结果:= CurrentTick - LastTick else 结果:=(高(Cardinal) - LastTick)+ CurrentTick; 结束

所以你有

StartTime:= GetTickCount ... 如果GetElapsedTime(StartTime)> 10000然后 ...

只要StartTime和当前的GetTickCount小于GetTickCount臭名昭着的49.7天范围。

Microsoft already says, in the documentation for GetTickCount, that you could never compare tick counts to check if an interval has passed. e.g.:

Incorrect (pseudo-code):

DWORD endTime = GetTickCount + 10000; //10 s from now ... if (GetTickCount > endTime) break;

The above code is bad because it is suceptable to rollover of the tick counter. For example, assume that the clock is near the end of it's range:

endTime = 0xfffffe00 + 10000 = 0x00002510; //9,488 decimal

Then you perform your check:

if (GetTickCount > endTime)

Which is satisfied immediatly, since GetTickCount is larger than endTime:

if (0xfffffe01 > 0x00002510)

The solution

Instead you should always subtract the two time intervals:

DWORD startTime = GetTickCount; ... if (GetTickCount - startTime) > 10000 //if it's been 10 seconds break;

Looking at the same math:

if (GetTickCount - startTime) > 10000 if (0xfffffe01 - 0xfffffe00) > 10000 if (1 > 10000)

Which is all well and good in C/C++, where the compiler behaves a certain way.

But what about Delphi?

But when i perform the same math in Delphi, with overflow checking on ({Q+}, {$OVERFLOWCHECKS ON}), the subtraction of the two tick counts generates an EIntOverflow exception when the TickCount rolls over:

if (0x00000100 - 0xffffff00) > 10000 0x00000100 - 0xffffff00 = 0x00000200

What is the intended solution for this problem?

Edit: i've tried to temporarily turn off OVERFLOWCHECKS:

{$OVERFLOWCHECKS OFF}] delta = GetTickCount - startTime; {$OVERFLOWCHECKS ON}

But the subtraction still throws an EIntOverflow exception.

Is there a better solution, involving casts and larger intermediate variable types?

Update

Another SO question i asked explained why {$OVERFLOWCHECKS} doesn't work. It apparently only works at the function level, not the line level. So while the following doesn't work:

{$OVERFLOWCHECKS OFF}] delta = GetTickCount - startTime; {$OVERFLOWCHECKS ON}

the following does work:

delta := Subtract(GetTickCount, startTime); {$OVERFLOWCHECKS OFF}] function Subtract(const B, A: DWORD): DWORD; begin Result := (B - A); end; {$OVERFLOWCHECKS ON}

解决方案

How about a simple function like this one?

function GetElapsedTime(LastTick : Cardinal) : Cardinal; var CurrentTick : Cardinal; begin CurrentTick := GetTickCount; if CurrentTick >= LastTick then Result := CurrentTick - LastTick else Result := (High(Cardinal) - LastTick) + CurrentTick; end;

So you have

StartTime := GetTickCount ... if GetElapsedTime(StartTime) > 10000 then ...

It will work as long as the time between StartTime and the current GetTickCount is less than the infamous 49.7 days range of GetTickCount.

更多推荐

Delphi:如何避免EIntOverflow下溢?

本文发布于:2023-10-24 20:51:10,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1524969.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:Delphi   EIntOverflow

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!