Разрешен ли динамический массив 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'

С чего бы это?

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


person Kenneth Cochran    schedule 23.09.2010    source источник
comment
Что ожидаемо? В первом случае массив не очищается.   -  person Andreas Rejbrand    schedule 23.09.2010
comment
Тем не менее, +1, поскольку компилируется только один из случаев (даже если мы используем AnsiChar), что довольно странно, поскольку между целым числом и AnsiChar очень мало различий.   -  person Andreas Rejbrand    schedule 23.09.2010
comment
@ Андреас, хорошо, ты меня понял. Пустому массиву нечего очищать. В моем тестовом коде был вызов SetLength, но я удалил его, поскольку он не имел прямого отношения к ошибке компиляции.   -  person Kenneth Cochran    schedule 23.09.2010
comment
Извините, если я что-то упустил, но в чем вопрос? Почему этот баг не исправлен?   -  person splash    schedule 23.09.2010
comment
@splash Значит, это ошибка компилятора, а не просто какое-то недокументированное ограничение параметров открытого массива?   -  person Kenneth Cochran    schedule 23.09.2010
comment
Я понимаю! Я пропустил тег [closed] в отчете CQ (может быть, это слишком поздно для меня), но если бы я догадался, я бы сказал, что это все та же ошибка. ;-)   -  person splash    schedule 23.09.2010


Ответы (3)


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

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

person Sertac Akyuz    schedule 24.09.2010

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

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), потому что, по крайней мере, это позволяет вам передавать массив в качестве ссылки, используя переменную, поэтому избегая создания копии в стеке. , и ускорьте свой код.

Что касается сопоставления с 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.

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

person Arnaud Bouchez    schedule 06.01.2011

Я думаю, причина в том, что 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.

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

--jeroen

person Jeroen Wiert Pluimers    schedule 23.09.2010
comment
Откуда P знает от MyArray? Не обманывайте указателями! ;-) - person splash; 23.09.2010
comment
Пока он компилируется, он на самом деле не работает. Процедура не знает, какова верхняя граница PChar. - person Sertac Akyuz; 24.09.2010
comment
@Sertac: я полностью согласен, что это где-то ошибка; просто хотел указать, откуда это могло взяться. Надеюсь, Барри или Дэнни прольют здесь свет. - person Jeroen Wiert Pluimers; 24.09.2010