würde ich diese Funktion wie so schreiben:
procedure Concat(var Dest: string; const Source: array of string);
var
i: Integer;
OriginalDestLen: Integer;
SourceLen: Integer;
TotalSourceLen: Integer;
DestPtr: PChar;
begin
TotalSourceLen := 0;
OriginalDestLen := Length(Dest);
for i := low(Source) to high(Source) do begin
inc(TotalSourceLen, Length(Source[i]));
end;
SetLength(Dest, OriginalDestLen + TotalSourceLen);
DestPtr := PChar(Pointer(Dest)) + OriginalDestLen;
for i := low(Source) to high(Source) do begin
SourceLen := Length(Source[i]);
Move(Pointer(Source[i])^, DestPtr^, SourceLen*SizeOf(Char));
inc(DestPtr, SourceLen);
end;
end;
Es ist ziemlich selbsterklärend. Die Komplikationen werden durch leere Strings verursacht. Jeder Versuch, Zeichen einer leeren Zeichenfolge zu indizieren, führt zu Ausnahmen, wenn die Bereichsüberprüfung aktiviert ist.
Um diese Komplikation zu behandeln, können Sie if
Tests für den Fall hinzufügen, in dem eine der Zeichenfolgen, die an dem -Aufruf beteiligt sind, leer ist. Ich bevorzuge einen anderen Ansatz. Ich würde die String-Variable lieber als Zeiger ausgeben. Dies umgeht die Bereichsüberprüfung, erlaubt aber auch das Auslassen der if
-Anweisung.
Move(Pointer(Source[i])^, DestPtr^, SourceLen*SizeOf(Char));
Man könnte sich fragen, was passiert, wenn Source[i]
leer ist. In diesem Fall ist Pointer(Source[i])
nil
und Sie könnten eine Zugriffsverletzung erwarten. In der Tat gibt es keinen Fehler, da die Länge der Verschiebung, wie durch das dritte Argument spezifiziert, Null ist, und der Zeiger nil
niemals tatsächlich de-referenziert wird.
Die andere Linie Bemerkenswert ist hier:
DestPtr := PChar(Pointer(Dest)) + OriginalDestLen;
Wir verwenden PChar(Pointer(Dest))
statt PChar(Dest)
. Letzterer ruft Code auf, um zu prüfen, ob Dest
leer ist oder nicht, und wenn dies der Fall ist, liefert er einen Zeiger auf einen einzelnen Null-Terminator. Wir möchten vermeiden, dass dieser Code ausgeführt wird, und die Adresse erhalten, die in Dest
direkt gehalten wird, selbst wenn es nil
ist.
Das RTL hat eine solche Funktion. Siehe '_LStrCatN' und sein Unicode-Pendant in * System.pas *. Der Compiler generiert automatisch Aufrufe an diese Funktion, wenn Sie mehr als drei Strings in einer einzigen Anweisung verketten, wie in 's1 + s2 + s3 + s4 + s5'. Die RTL-Funktion hat nicht dieselbe Schnittstelle; Es akzeptiert seine Liste von Zeichenfolgen auf dem Stapel statt als ein Array. Sie können die RTL-Funktion nicht direkt aufrufen, wenn Sie keine Baugruppe schreiben. –