Se permite una matriz dinámica de Char cuando el tipo de parámetro es array abierto de Char?
-
04-10-2019 - |
Pregunta
Me estaba mirando Delphi: arreglo de char y TCharArray "tipos incompatibles" y comenzó a experimentar. Lo que descubrí es bastante interesante.
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.
Este pequeño y sencillo ejemplo muestra cómo se puede pasar una matriz dinámica a un procedimiento que utiliza un parámetro de matriz abierta. Se compila y se ejecuta como se esperaba exactamente.
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.
Aquí es código casi idéntica la única diferencia de que está utilizando una gran variedad de Char
en lugar de Integer
. No compila. En cambio, el compilador escupe:
E2010 Incompatible types: 'Array' and 'Dynamic array'
¿Por qué sería?
Después de buscar durante un tiempo descubrí este informe de control de calidad . Estoy corriendo Delphi 2009 y su todavía sucediendo.
Solución
Since the documentation specifically mentions open array parameters of type Char to be compatible with dynamic arrays, this should be a bug. From 'Open Array Parameters':
function Find(A: array of Char):
Integer;
[...]
Note: [...] The previous example creates a function that takes any array of Char elements, including (but not limited to) dynamic arrays. [...]
Otros consejos
You can work with this kind of array, defining your own type:
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;
This code will compile fine. It doesn't do anything useful of course (the AArray parameter is not set as "var", so it's copied on the stack before assigning a #0 to every item). But at least, it compiles.
In practice, I found out more easy to define or use high-level of types for dynamic arrays (like TIntegerDynArray), because at least it allows you to pass the array as reference, using a var, therefore avoiding to make a copy on stack, and make your code faster.
About the mapping to a PChar, it's usual for all dynamic arrays: you can map a TIntegerDynArray to a pointer, then use it as a PInteger or a 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.
The problem is the "array of char" code beeing inconsistent with "array of integer" is certainly in compiler intrinsics, and the fact that a PChar can be type-casted to a string.
I think the reason is that array of Char
is compatible with PChar
, as this code does compile:
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.
That is probably for historic reasons.
Hopefully Barry Kelly or Danny Thorpe will kick in and provide some more feedback on this.
--jeroen