Delphi 11.2中出现整数溢出错误,但Delphi 10.4.2中没有

pwuypxnk  于 2023-01-08  发布在  其他
关注(0)|答案(1)|浏览(119)

我正在尝试将一个旧的pascal程序从 Delphi 转换成Delphi11.2Alexandria。
我有下面的函数,它用A的倍数填充模表,模是Array [0..255, 0..19] of Byte

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
      ModuloPointer^:= ((NPointer^ * I) + Remainder);  //<- Int Overflow error

      WordPointer:= Pointer(NPointer);
      Remainder:= ((WordPointer^ * I) + Remainder) div $10000;             
      Inc(WordPointer);
      Remainder:= ((WordPointer^ * I) + Remainder) div $10000;              

      Inc(NPointer);
      Inc(ModuloPointer);
    end;
    ModuloPointer^:= Remainder;
  end;
end;

程序参数TCode128为Array[0..15] of Byte,发送字节地址为($12, $C4.......)
在 Delphi 中,我在ModuloPointer^:= ((NPointer^ * I) + Remainder);处得到一个整数溢出错误。当它抛出错误时,I的值正好是2。
当我在 Delphi 上运行相同的过程时,没有整数溢出错误,一切都很好。
我真的想不出这里出了什么问题,我试着将ModuloPointerNPointer类型转换为Uint64,将Modulo类型转换为Word,但没有成功(可能没有意义)。
我是否遗漏了一些非常简单的东西,或者 Delphi 11.2 IDE中有一些变化?无论如何,我们如何解决这个问题,哪里出了问题?

lh80um4z

lh80um4z1#

指针杂耍的等价形式是:

type
  TCode128= packed record
    case Byte of  // The same length for all variants, equal to UNIONs in C
    1: ( b: Array[0.. 15] of Byte );  // Accessing as 16 bytes
    2: ( c: Array[0.. 3] of Cardinal );  // As 4 DWORDs
    3: ( w: Array[0.. 7] of Word );  // As 8 WORDs
  end;

var
  Modulo: Array[0.. 255] of Array[0.. 4] of Cardinal;  // DWORDs where we need them

procedure SetModulo( A: TCode128 );
var
  I, J, Remainder: Byte;
begin
  for I:= 0 to 255 do begin  // For each "modulo"
    Remainder:= 0;
    for J:= 0 to 3 do begin  // Each first 4 remainders
      // Access and store as DWORDs right away
      // Allowing a higher product/sum than CARDINAL could hold, but only store 32 bit
      Modulo[I][J]:= (Int64(A.c[J])* I+ Remainder) and $FFFFFFFF;

      Remainder:= (A.w[J* 2]* I+ Remainder) div $10000;  // Access as WORDs
      Remainder:= (A.w[J* 2+ 1]* I+ Remainder) div $10000;
    end;
    Modulo[I][4]:= Remainder;  // Last 5th remainder
  end;
end;

正如你所看到的,这在逻辑上更容易理解,需要更少的变量,并且是平台无关的。TCode128定义有3个变量,但是它们都指向同一个内存-这样你就可以用多种方式定义内存,以便以后访问它,这对大脑和数据类型都更友好。
Cardinal乘以255,然后在最大255处相加,很容易产生溢出,因为它只适用于16843008$1010100)以内的值,这就是为什么我只选择乘积/和的(最小)32位。

相关问题