2010-09-23 9 views
11

Ich schaute auf Delphi: array of Char and TCharArray "Incompatible Types" und begann zu experimentieren. Was ich entdeckt habe, ist ziemlich interessant.Ist ein dynamisches Array von Char erlaubt, wenn der Parametertyp ein offenes Array von Char ist?

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. 

Dieses einfache Beispiel zeigt, wie Sie ein Dynamic Array an eine Prozedur übergeben können, die einen Open Array-Parameter verwendet. Es kompiliert und läuft genau wie erwartet.

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. 

ist hier fast identischen Code der einzige Unterschied ist es eine Reihe von Char statt Integer verwendet. Es kompiliert nicht. Stattdessen spuckt der Compiler aus:

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

Warum sollte das sein?

Nach der Suche nach einer Weile habe ich this QC-Bericht entdeckt. Ich betreibe Delphi 2009 und es passiert immer noch.

+0

Was ist "wie erwartet"? Das Array wird im ersten Fall nicht gelöscht. –

+0

Dennoch, +1, nur für einen der Fälle kompilieren (auch wenn wir 'AnsiChar' verwenden), was ziemlich seltsam ist, da es einen sehr kleinen Unterschied zwischen einer Ganzzahl und einem' AnsiChar' gibt. –

+0

@Andreas, Ok du hast mich da. Ein leeres Array hat nichts zu löschen. Mein Testcode hatte einen Aufruf von SetLength, aber ich entfernte ihn, da er für den Kompilierungsfehler nicht direkt relevant war. –

Antwort

4

Da die Dokumentation speziell offene Array-Parameter vom Typ char erwähnt mit dynamischen Arrays kompatibel zu sein, sollte dies ein Fehler sein. Von 'Open Array Parameters':

function Find(A: array of Char): Integer;
[...]
Anmerkung: [...] Das vorherige Beispiel wird eine Funktion, die jede Array von Char Elementen nimmt, einschließlich (aber nicht beschränkt auf) dynamischen Arrays. [...]

2

Ich denke, der Grund ist, dass array of Char mit PChar kompatibel ist, wie dieser Code kompilieren tut:

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. 

, die wahrscheinlich aus historischen Gründen ist.
Hoffentlich Barry Kelly oder Danny Thorpe werden in kicken und bieten mehr Feedback dazu.

--jeroen

+0

Woher kennt 'P'' MyArray'? Nicht mit Zeigern schummeln! ;-) – splash

+3

Während es kompiliert, funktioniert es nicht wirklich. Das Verfahren hat keine Ahnung, wie hoch der PChar ist. –

+0

@Sertac: Ich stimme völlig zu, dass es irgendwo ein Fehler ist; wollte nur darauf hinweisen, wo es herkommen könnte. Hoffentlich werden Barry oder Danny hier Licht spenden. –

4

Sie können mit dieser Art von Array arbeiten, Ihre eigene Art definieren:

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; 

Dieser Code wird fein kompilieren. Es macht natürlich nichts Sinnvolles (der AArray-Parameter wird nicht als "var" gesetzt, also wird er auf den Stapel kopiert, bevor jedem Gegenstand eine # 0 zugewiesen wird). Aber zumindest kompiliert es.

In der Praxis fand ich mehr einfach zu definieren oder verwenden High-Level-Typen für dynamische Arrays (wie TIntegerDynArray), weil zumindest ermöglicht es Ihnen, das Array als Verweis übergeben, mit einer Var, daher zu vermeiden eine Kopie auf Stapel, und machen Sie Ihren Code schneller.

Über die Zuordnung zu einem PChar, ist es üblich, für alle dynamischen Arrays: Sie TIntegerDynArray auf einen Zeiger zuordnen kann, dann als PInteger verwenden oder ein 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. 

Das Problem ist die „Array Der Code "char" ist inkonsistent mit "Array of Integer" ist sicherlich in Compiler intrinsics, und die Tatsache, dass ein PChar kann zu einem String Typ-Casted sein.