プロシージャで動的配列を使用するには、配列のMove
最初の要素を渡す必要があります。例えば:
var
Source: Pointer;
SourceSize: Integer;
Destination: array of Byte;
SetLength(Destination, SourceSize);
Move(Source^, Destination[0], SourceSize);
2 番目のパラメーターがポインターを逆参照することにも注意してください。これは、値へのポインターではなく、コピーしている値Move
を取るためです。ポインタが指すものをコピーしているので、それを に渡す必要があります。Move
ちなみに、 がDestination
静的配列の場合も同じ構文が機能します。そして、これは Delphi 2009 に固有のものではないということは正しいです。これは、動的配列が導入された Delphi 4 までずっと当てはまります。そしてMove
、同じ奇妙な型指定されていないパラメーター構文が永遠にありました。
独自のメモリを割り当ててGetMem
から型キャストして、コンパイラに動的配列であると認識させないでください。そうではありません。動的配列には、通常のバイトバッファーにはない参照カウントと長さフィールドがあります。また、想定される動的配列にアクセスするためにコンパイラーが生成するすべてのコードを制御できないため、プログラムがアクセスしようとする危険があります。データ構造の存在しないデータ。
PSP 関数でそのデータを直接動的配列に格納することができます。これを行うコードは次のとおりです。
var
Output: array of Byte;
SetLength(Output, OutputLength.Value);
if SendPSPQuery(Char(DriveLetter[1]),
cbxQuery.Items.IndexOf(cbxQuery.Text),
@Output[0],
OutputLength.Value) = 0
then
後でメモリを解放する必要はありません。Output
スコープ外になり、配列への参照が他にない場合、コンパイラは動的配列の割り当てを解除するコードを挿入します。このコードは、動的配列を取り、通常のバッファーであるかのように渡します。動的配列は事実上、単純な古いバッファのサブタイプであるため、これは機能し、安全です。関数は、配列の最初の要素へのポインターを受け入れ、そのポインターを一連のバイトへのポインターとして扱います。関数は、プログラムが動的配列のブックキーピングに使用するバイトに隣接する追加の要素があることを知る必要はありません。
バッファーにデータがあり、データを別のデータ構造にコピーするのではなく、そのバッファーを配列のように扱いたい場合は、2 つのオプションがあります。
static-array pointerを宣言してから、バッファー ポインターをその型に型キャストします。これは古典的な手法であり、あらゆる場所のコード、特に Delphi 4 より前のコードで使用されていることがわかります。次に例を示します。
type
PByteArray = ^TByteArray;
TByteArray = array[0..0] of Byte;
var
ByteArray: PByteArray;
ByteArray := PByteArray(Output);
for i := 0 to Pred(OutputLength.Value) do begin
{$R-}
edtString.Text := edtString.Text + Chr(ByteArray[i]);
{$R+}
end;
ディレクティブは、配列型の長さが1であると宣言されているため、そのコードの$R
範囲チェックがオフになっていることを確認することです。配列は、実際に宣言する必要がないという手がかりとして機能するように、そのサイズで宣言されていますその型の変数。ポインターを介してのみ使用してください。一方、データの適切な最大サイズがわかっている場合は、代わりにそのサイズを使用して配列型を宣言し、範囲チェックを有効にしておくことができます。(通常、範囲チェックを無効にしている場合は、トラブルを求めているだけです。)
PByte
代わりにバッファーを宣言し、任意のポインター型を配列ポインターとして扱うためPointer
の Delphi の新しい (Delphi 2009 以降)サポートを使用します。以前のバージョンでは、、、およびのみがこの構文をサポートしていました。例えば:PChar
PAnsiChar
PWideChar
var
Output: PByte;
for i := 0 to Pred(OutputLength.Value) do begin
edtString.Text := edtString.Text + Chr(Output[i]);
end;
そのディレクティブが有効なときにその型が宣言さ$POINTERMATH
れるため、この機能を有効にするためにコンパイラ ディレクティブは必要ありません。他のポインター型でC のようなポインター操作を行いたい場合は、新しい拡張構文を使用するコードの前に配置します。PByte
{$POINTERMATH ON}
最後に、文字列を一度に 1 文字ずつ作成する必要はありません。2つの意味で無駄です。まず、多数の文字列を作成しています。それぞれの文字列は、前の文字列よりわずか 2 バイト大きくなっています。2 つ目は、文字列の結果をエディット コントロールに格納しているため、そのコントロールの OS 実装に一連の新しい文字列の割り当ても強制しています。データを1 つの文字列に入れ、編集コントロールに一度に追加します。
var
OutputString: AnsiString;
SetString(OutputString, PAnsiChar(Buffer), OutputLength.Value);
edtString.Text := edtString.Text + OutputString;