为什么访问动态数组的越界索引不会引起AV?

时间:2015-10-19 08:52:09

标签: delphi delphi-xe2

在VCL中,TByteDynArray被定义为动态数组:

type TByteDynArray = array of Byte;

但似乎没有完成索引边界检查:

var
  DataBytes: System.Types.TByteDynArray;
  i: Integer;
begin
  SetLength(DataBytes, 2);
  DataBytes[5] := 222; // Accessing index beyond set length.
  i := DataBytes[5]; // `i` is now set to "222".

上面的代码运行没有错误。

为什么没有引发AccessViolation,就像使用静态数组一样?如果您可以访问和修改数组变量的65536字节内存而不考虑长度设置,那么SetLength的重点是什么?

1 个答案:

答案 0 :(得分:6)

要检测超出范围错误的数组索引,请设置范围检查错误。

Range Checking

  

$ R指令启用或禁用范围检查代码的生成。在{$ R +}状态中,所有数组和字符串索引表达式都被验证为在定义的范围内,并且所有对标量和子范围变量的赋值都被检查在范围内。如果范围检查失败,则引发ERangeError异常(或者如果未启用异常处理则终止程序。)

这是默认设置为{$ R-},但我建议将其设置为开启,至少在开发阶段。 它为代码增加了额外的开销,因此这可能是它默认关闭的原因。

如果您的设备经过良好测试并希望避免范围检查,请在设备顶部添加{$ R-}。这将在本地覆盖项目设置。

如果要避免代码块中的范围检查,可以使用此技术:

{$IFOPT R+}
  {$DEFINE RestoreRangeCheck}
  {$R-}
{$ENDIF}

{- Some code here }

{$IFDEF RestoreRangeCheck}
  {$R+}
  {$UNDEF RestoreRangeCheck}
{$ENDIF}