为什么 Delphi 和 FreePascal 编译器对基于 0 和基于 x 的静态数组的处理方式不同?

Vas*_*lis 1 delphi freepascal lazarus

program test;

uses
  sysutils;

const
  BUFLEN = 20;

var
  Buf0: array[0..BUFLEN-1] of char;
  Buf1: array[1..BUFLEN] of char;
  s: string;

begin
    // Fillchar...
    // StrPLCopy...

    SetString(s, Buf1, Length(Buf1));
    // Error: Incompatible type for arg no. 2: Got "Array[1..20] Of Char", expected "PChar"

    SetString(s, Buf0, Length(Buf0));
    // compiles ok
end.
Run Code Online (Sandbox Code Playgroud)

在 C/C++ 中,我们经常使用数组名作为指针。在 Delphi 中,我们也可以像上面的例子那样实现。

尽管如此,Buf1在 FreePascal 中使用数组SetString()会导致错误,而Buf0数组工作得很好。数组的基本索引应该无关紧要,对吗?

是否有任何文件证明这种行为是合理的

在 FPC 3.0.4 和 Delphi 10.3 中测试。

Hea*_*are 6

如果查看链接到的定义,第二个参数可以是以下类型之一:

  Buf: PAnsiChar;
  Buf: PWideChar;
  Buf: PChar;
  Buf: PUnicodeChar;
  Buf: PChar;
  Buf: PWideChar;
  Buf: PChar;
Run Code Online (Sandbox Code Playgroud)

如果您删除重复项/别名,您将获得以下可能性:

  Buf: PAnsiChar;
  Buf: PWideChar;
  Buf: PUnicodeChar;
Run Code Online (Sandbox Code Playgroud)

在 {$X+} 状态下,有一个内置的类型兼容性:

PAnsiChar <-> ARRAY[0..nn] OF AnsiChar
PWideChar <-> ARRAY[0..nn] OF WideChar
PUnicodeChar <-> ARRAY[0..nn] OF UnicodeChar
Run Code Online (Sandbox Code Playgroud)

正如您在上面看到的,所有与 PChar 类型兼容的 Char 数组都具有较低的索引 0。这就是编译器类型兼容性的工作原理。这样做的原因是这种类型的兼容性主要是为了更容易地转换 C(++) 代码,而 C(++) 没有能力指定(普通)数组的下限——它们总是 0 .

因此,在 Delphi / FreePascal 中也是如此,以保持(尽可能)与 C(++) 兼容。