Подтвердить что ты не робот

Является ли динамический массив Char допустимым, когда тип параметра является открытым массивом Char?

Я смотрел Delphi: массив Char и TCharArray "Несовместимые типы" и начал экспериментировать. То, что я обнаружил, довольно интересно.

procedure Clear(AArray: array of Integer);
var
  I: Integer;
begin
  for I := Low(AArray) to High(AArray) do
    AArray[I] := 0;
end;

var
  MyArray: array of Integer;
begin
  Clear(MyArray);
end.

Этот простой пример показывает, как вы можете передать динамический массив процедуре с использованием параметра Open Array. Он компилируется и работает точно так, как ожидалось.

procedure Clear(AArray: array of Char);
var
  I: Integer;
begin
  for I := Low(AArray) to High(AArray) do
    AArray[I] := #0;
end;

var
  MyArray: array of Char;
begin
  Clear(MyArray);
end.

Здесь почти идентичный код, единственное отличие состоит в том, что он использует массив Char, а не Integer. Он не компилируется. Вместо этого компилятор выплевывает:

 E2010 Incompatible types: 'Array' and 'Dynamic array'

Почему это должно быть?

После некоторого поиска я обнаружил этот отчет о QC. Я запускаю Delphi 2009 и все еще происходит.

4b9b3361

Ответ 1

Поскольку в документации специально упоминаются параметры открытого массива типа Char для совместимости с динамическими массивами, это должно быть ошибкой. Из 'Параметры открытого массива:

function Find(A: array of Char):Integer;
[...]
Примечание: [...] Предыдущий пример создает функцию который принимает любой массив элементов Char, включая (но не ограничиваясь) динамические массивы. [...]

Ответ 2

Вы можете работать с таким массивом, определяя свой собственный тип:

type
  TCharDynArray = array of char;

procedure Clear(AArray: TCharDynArray);
var
  I: Integer;
begin
  for I := Low(AArray) to High(AArray) do
    AArray[I] := #0;
end;

procedure test;
var
  MyArray: TCharDynArray;
begin
  Clear(MyArray);
end;

Этот код будет скомпилирован. Разумеется, это не делает ничего полезного (параметр AArray не задан как "var", поэтому он копируется в стек перед назначением # 0 для каждого элемента). Но, по крайней мере, он компилируется.

На практике я обнаружил более легкое определение или использование высокоуровневых типов для динамических массивов (например, TIntegerDynArray), поскольку, по крайней мере, он позволяет передавать массив как ссылку, используя var, поэтому избегая скопировать в стек и сделать код быстрее.

Об отображении на PChar, это обычно для всех динамических массивов: вы можете сопоставить TIntegerDynArray с указателем, а затем использовать его как PInteger или PIntegerArray:

procedure AddInteger(var Values: TIntegerDynArray; Value: integer);
var n: integer;
begin
  n := Length(Values);
  SetLength(Values,n+1);
  Values[n] := Value;
end;

procedure Loop(V: PInteger);
begin
  if V<>nil then
    while V^<>0 do begin
      write(V^,' ');
      inc(V); // go to next integer in array
    end;
end;

var IntArray: TIntegerDynArray;
begin
  Loop(pointer(IntArray)); // will display nothing, since pointer(IntArray)=nil for IntArray=[]
  AddInteger(IntArray,2);
  AddInteger(IntArray,3);
  AddInteger(IntArray,0);
  Loop(pointer(IntArray)); // will display '2 3 '  
end.

Проблема заключается в том, что код "массив из char", несовместимый с "массивом целого числа", безусловно, связан с внутренними функциями компилятора, а также тот факт, что PChar может быть введен в строковое выражение для строки.

Ответ 3

Я думаю, причина в том, что array of Char совместим с PChar, так как этот код компилируется:

procedure Clear(AArray: array of Char);
var
  I: Integer;
begin
  for I := Low(AArray) to High(AArray) do
    AArray[I] := #0;
end;

var
  MyArray: array of Char;
  P: PChar;
begin
  Clear(P^);
end.

Это, вероятно, по историческим причинам.
Надеюсь, Барри Келли или Дэнни Торп выступит и предоставит еще несколько отзывов об этом.

- Йерун