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

Why accessing out-of-bounds indices of dynamic array doesn't raise AV?

在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 有什么意义?

要检测数组索引越界错误,请将范围检查错误设置为开。

Range Checking

The $R directive enables or disables the generation of range-checking code. In the {$R+} state, all array and string-indexing expressions are verified as being within the defined bounds, and all assignments to scalar and subrange variables are checked to be within range. If a range check fails, an ERangeError exception is raised (or the program is terminated if exception handling is not enabled).

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


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

如果您想避免在代码块中进行范围检查,可以使用以下技术:

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

{- Some code here }

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