Delphi 11.2出现Integer overflow error,10.4.2无此问题的原因及解决
问题原因与解决方案
原因分析
- 溢出检查默认行为变更:Delphi 11.2默认开启了整数溢出检查(
{$OVERFLOWCHECKS ON}),而Delphi 10.4.2及更早版本默认关闭该检查。你的代码中NPointer^ * I的计算会产生超过32位无符号整数(Cardinal)范围的值,旧版本编译器会直接截断溢出部分,新版本则严格触发溢出错误。 - 类型计算的隐式溢出:
NPointer^是32位无符号类型,I是8位无符号类型,两者相乘的最大可能值($FFFFFFFF * 255)远超过32位无符号数的上限,必然触发溢出。
解决方案
方案1:临时禁用溢出检查(最快适配旧逻辑)
在触发溢出的代码段前后添加编译器指令,临时关闭溢出检查,和旧版本行为保持一致:
procedure TForm.SetModulo(A: TCode128); var I, J, Remainder : Byte; NPointerStart: PCardinal; NPointer: PCardinal; ModuloPointer: PCardinal; WordPointer: PWord; begin NPointerStart:= Addr(A); for I:= 0 to 255 do begin NPointer:= Pointer(NPointerStart); Remainder:= 0; ModuloPointer:= Addr(Modulo[I][0]); for J:= 0 to 3 do begin {$OVERFLOWCHECKS OFF} // 临时关闭溢出检查 ModuloPointer^:= ((NPointer^ * I) + Remainder); {$OVERFLOWCHECKS ON} // 恢复溢出检查 {$OVERFLOWCHECKS OFF} WordPointer:= Pointer(NPointer); Remainder:= ((WordPointer^ * I) + Remainder) div $10000; Inc(WordPointer); Remainder:= ((WordPointer^ * I) + Remainder) div $10000; {$OVERFLOWCHECKS ON} Inc(NPointer); Inc(ModuloPointer); end; ModuloPointer^:= Remainder; end; end;
方案2:使用64位类型承载计算(更安全的写法)
通过将计算过程转换为64位整数(Int64),避免溢出,再转换回目标类型,既兼容旧逻辑又符合新版本的安全要求:
procedure TForm.SetModulo(A: TCode128); var I, J, Remainder : Byte; NPointerStart: PCardinal; NPointer: PCardinal; ModuloPointer: PCardinal; WordPointer: PWord; Temp: Int64; // 用64位变量承载计算,避免溢出 begin NPointerStart:= Addr(A); for I:= 0 to 255 do begin NPointer:= Pointer(NPointerStart); Remainder:= 0; ModuloPointer:= Addr(Modulo[I][0]); for J:= 0 to 3 do begin // 用Int64计算,避免溢出 Temp := Int64(NPointer^) * I + Remainder; ModuloPointer^:= Cardinal(Temp); // 截断回32位,和旧逻辑一致 WordPointer:= Pointer(NPointer); Temp := Int64(WordPointer^) * I + Remainder; Remainder:= Byte(Temp div $10000); Inc(WordPointer); Temp := Int64(WordPointer^) * I + Remainder; Remainder:= Byte(Temp div $10000); Inc(NPointer); Inc(ModuloPointer); end; ModuloPointer^:= Remainder; end; end;
额外说明
你之前尝试强制转换指针为Uint64没解决问题,是因为你需要转换的是指针指向的值,而非指针本身的地址。另外,你用PCardinal指向Byte数组的写法是合理的,每次赋值会连续写入4个Byte,刚好匹配Modulo[I][0]到Modulo[I][3]的存储范围。
内容的提问来源于stack exchange,提问作者fuzzhead
相关产品推荐
相关产品推荐

