Delphi Programming / Object Pascal
[掲載 2018年06月09日] [更新 2021年02月25日] Delphi 一般・その他 |
PByte 型バイト列と Byte 型配列 |
動作確認等 |
Windows 7 U64(SP1) + Delphi XE5(UP2) Pro VCL-32 |
PByte 型は,任意のバイトデータのポインタ用の型です.
Windwos API で扱う変数の型はポインタ型です.PByte 型は,Windows API の関数からバイト列のデータを受け取ったり,バイト列のデータを渡す際にも使われることがあります.
本ページは,主に PByte 型のバイト列のデータの操作に関するサンプルです. |
PByte 型は Byte 型のポインタ型です.PByte 型変数の逆参照が Byte 型の値となります.Byte 型の変数値のアドレスが,PByte 型変数のポインタとしての値になります.
以下のサンプルはこのことを確認するサンプルコードです.下図の実行結果の 2 番目の値は,結果のバイト値のアドレスの値を表示しています. |
|
図1
PBYte 型変数に Byte 型変数をセット |
|
図2
Byte 型変数に PByte 型変数をセット |
//=============================================================================
// PByte型の値をTByte型の値に変換
// 逆参照値を代入する
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LPByte : PByte;
LByte : Byte;
begin
Memo1.Lines.Clear;
// ポインタ型の変数はメモリの確保が必要
New(LPByte);
try
LPByte^ := $0C;
LByte := LPByte^;
Memo1.Lines.Add('PByte 型の変数に Byte 型の値を代入');
Memo1.Lines.Add('$' + LByte.ToHexString(2));
//アドレス表示
//IntToHexは整数型の値を16進数表示の文字列に変換する
Memo1.Lines.Add('$' + IntToHex(NativeUInt(@LByte), 8));
finally
Dispose(LPByte);
end;
end;
//=============================================================================
// Byte型の値をPByte型の値に変換
// アドレスを代入する
// ポインタ型の変数に変数のアドレスを代入するのでメモリの確保は不要
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LByte : Byte;
LPByte : PByte;
begin
Memo1.Lines.Clear;
Memo1.Lines.Add('Byte 型の変数に PByte 型の値を代入');
LByte := $FA;
LPByte := @LByte;
Memo1.Lines.Add('$' + LPByte^.ToHexString(2));
//アドレス表示
//IntToHexは整数型の値を16進数表示の文字列に変換する
Memo1.Lines.Add('$' + IntToHex(NativeUInt(LPByte), 8));
end;
[備考]
上の Button1 クリックのコートのように,ポインタ型の変数を独立した変数として使用する場合は,そのポインタ型変数のメモリの確保が必要です.
上のサンプルコード程度であれば,メモリを確保しなくても例外が発生することはありません.しかし,実際のアプリはこんなに単純なコードだけとは限りません. |
バイト型の配列にセットした値を,Move 関数を使用して PByte 型のバイト列のデータとしてメモリに書き込んでいくサンプルです.
下図はメモリに書き込んだバイト値を順番に読み出して表示した結果です.
PByte 型は配列ではありませんから,配列要素の番号では操作できません.inc 関数や dec 関数を使用してポインタ (メモリ上の格納位置) を移動することによりバイト値をメモリに書き込んだり,読み込んだりします.
TBytes は動的なバイト配列の型です.Byte は 1 バイトのバイトデータの型です. |
|
図3
バイト配列データを PByte 型のバイト列に変換 |
//=============================================================================
// TBytes型バイト配列のバイトデータをPByte型のバイト列としてメモリに格納
//
// TBytesはバイト型の動的配列
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LBytes : TBytes;
LPByte : PByte;
LPByteDst : PByte;
LBytevalue : Byte;
LSize : Integer;
LIndex : Integer;
begin
Memo1.Lines.Clear;
Memo1.Lines.Add('TBytes 型バイト配列のデータを PByte 型バイト列に');
SetLength(LBytes, 7);
//テスト用のデータをバイト配列に格納
for LIndex := Low(LBytes) to High(LBytes) do begin
LBytes[LIndex] := Byte((LIndex + 5));
end;
//バイト列のメモリ領域を確保
LSize := Length(LBytes);
LPByte := AllocMem(LSize);
try
//バイト配列のデータを確保したメモリにコピー
Move(LBytes[0], LPByte^, LSize);
//確認のためLPByteのデータを表示
//バイト列の先頭ポインタをLPByteDstとする
LPByteDst := LPByte;
//メモリに格納したバイトデータを順番に取り出して表示
for LIndex := 0 to LSize - 1 do begin
LBytevalue := Byte(LPByteDst^);
Memo1.Lines.Add('$' + LByteValue.ToHexString(2));
//バイトデータのポインタをインクリメント
inc(LPByteDst);
end;
finally
FreeMem(LPByte);
end;
end;
上のサンプルとは逆に,PBytes 型でメモリに格納したバイト列の値を,Move 関数を使用してバイト配列に格納するサンプルです.
下図はバイト配列に格納された値を順番に表示した結果です. |
|
図4
PByte 型のバイト列をバイト配列に格納 |
//=============================================================================
// PByte型バイト列データをTBytesの型バイト配列データの各要素に格納
//
// TBytesはバイト型の動的配列
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LBytes : TBytes;
LPByte : PByte;
LPByteDst : PByte;
LBytevalue : Byte;
LSize : Integer;
LIndex : Integer;
begin
Memo1.Lines.Clear;
Memo1.Lines.Add('PByte 型バイト列を TBytes 型バイト配列のデータに');
//バイト列のメモリ領域を確保
LSize := 7;
LPByte := AllocMem(LSize);
try
//バイト列の先頭ポインタをLPByteDstとする
LPByteDst := LPByte;
//テスト用のデータを確保したメモリにバイト単位で値を格納
for LIndex := 0 to LSize - 1 do begin
LPByteDst^ := Byte(LIndex + $0B);
//バイト列のポインタをインクリメント
inc(LPByteDst);
end;
//バイト配列のサイズを設定
SetLength(LBytes, LSize);
//メモリ上のバイト列をバイト配列の要素にコピー
Move(LPByte^, LBytes[0], LSize);
//確認表示
//バイト配列に格納したデータを順番に表示
for LIndex := Low(LBytes) to High(LBytes) do begin
LBytevalue := LBytes[LIndex];
Memo1.Lines.Add('$' + LByteValue.ToHexString(2));
end;
finally
FreeMem(LPByte);
end;
end;
02_PByte 型バイト列と TStringStream のデータとの変換 |
TStringStream に書き込んだバイト配列としてのデータを,TStringStream の ReadBuffer メソッドを使用して PByte 型のバイト列のデータとしてメモリに書き込むテストです.
メモリに書き込んだバイトデータを順番に読み込んで表示します. |
|
図5
TStringStream のデータを PByte 型のバイト列に変換 |
//=============================================================================
// TStringStreamのデータをPByte型のバイト列データとしてメモリに格納
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LStrStream : TStringStream;
LPByte : PByte;
LPByteDst : PByte;
LBytevalue : Byte;
LSize : Integer;
LIndex : Integer;
begin
Memo1.Lines.Clear;
Memo1.Lines.Add('TStringStream のデータを PByte 型のバイト列に');
LStrStream := TStringStream.Create;
try
//テスト用のデータをTStringStreamのストリームにに格納
LSize := 7;
LStrStream.SetSize(LSize);
for LIndex := 0 to LSize - 1 do begin
LStrStream.Bytes[LIndex] := Byte((LIndex + 5));
end;
//バイト列データ用のメモリ領域を確保
LSize := LStrStream.Size;
LPByte := AllocMem(LSize);
try
//TStringSreamのストリームのデータを確保したメモリに書き込む
LStrStream.ReadBuffer(LPByte^, LSize);
//バイト列の先頭ポインタをLPByteDstとする
LPByteDst := LPByte;
//確認表示
//メモリに格納したバイト列データを順番に取り出して表示
for LIndex := 0 to LSize - 1 do begin
LBytevalue := Byte(LPByteDst^);
Memo1.Lines.Add('$' + IntToHex(LBytevalue, 2));
//バイト列のポインタをインクリメント
inc(LPByteDst);
end;
finally
FreeMem(LPByte);
end;
finally
FreeAndNil(LStrStream);
end;
end;
上とは逆に,PByte 型のバイト列としてメモリに格納したバイト列を,TStringStream.WriteBuffer メソッドで TStringStream に書き込むテストです.
TStringStream のストリームに書き込んだデータを順番に表示します. |
|
図6
PByte 型のバイト列を TStringStream のデータに変換 |
//=============================================================================
// PByte型バイト列をTStringStreamで読み込む
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LStrStream : TStringStream;
LPByte : PByte;
LPByteDst : PByte;
LBytevalue : Byte;
LSize : Integer;
LIndex : Integer;
begin
Memo1.Lines.Clear;
Memo1.Lines.Add('PByte 型のバイト列を TStringStream のデータに');
//バイト列データのメモリ領域を確保
LSize := 7;
LPByte := AllocMem(LSize);
try
//バイト列の先頭ポインタをLPByteDstとする
LPByteDst := LPByte;
//テスト用のデータを確保したメモリにバイト単位で値を格納
for LIndex := 0 to LSize - 1 do begin
LPByteDst^ := Byte(LIndex + $0B);
//バイト列のポインタをインクリメント
inc(LPByteDst);
end;
LStrStream := TStringStream.Create;
try
//メモリのバイト列データをTStrainStreamのストリームに書き込む
LStrStream.WriteBuffer(LPByte^, LSize);
//確認表示
//TStringStreamに格納したデータを順番に表示
for LIndex := 0 to LSize - 1 do begin
LBytevalue := LStrStream.Bytes[LIndex];
Memo1.Lines.Add('$' + IntToHex(LBytevalue, 2));
end;
finally
FreeAndNil(LStrStream);
end;
finally
FreeMem(LPByte);
end;
end;
次も TStringStream と PByte 型のバイト列データの変換のサンプルです.
テスト用として AnsiString 型の ASCII 文字だけを使用しています.AnsiString 型の ASCII 文字は 1 バイト文字です.
文字列を TStringStream にバイトデータとして書き込みます.そのデータを PByte 型のバイト列としてメモリに格納します.その後,別の TStringStream でメモリ上に格納されたバイト列データを読み込みます.
TMemo に文字列を表示する際,string で型キャストしています.これは「W1057 文字列の暗黙のキャスト ('AnsiString' から 'string')」という警告を表示しないようにするためです. |
|
図7
TStringStream のバイト配列データと PByte 型のバイト列の変換
- AnsiString 型の 1 バイトの文字列を使用
|
//=============================================================================
// TStringStreamにおけるPByte型バイト列の読み書き
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LTextSrc : AnsiString;
LTextDst : AnsiString;
LStrStreamSrc : TStringStream;
LStrStreamDst : TStringStream;
LPByte : PByte;
LSize : Integer;
begin
Memo1.Lines.Clear;
//テスト用バイトデータ
LTextSrc := 'ABCDEFGHIJK';
LStrStreamSrc := TStringStream.Create;
LStrStreamDst := TStringStream.Create;
try
//テスト列データをストリームに書き込む
LSize := Length(LTextSrc);
LStrStreamSrc.WriteBuffer(LTextSrc[1], LSize);
LPByte := AllocMem(LStrStreamSrc.Size);
try
//TStringStreamに格納されているデータをPByt型のバイト列としてメモリに格納
LStrStreamSrc.Position := 0;
LSize := LStrStreamSrc.Read(LPByte^, LStrStreamSrc.Size);
//そのPByte型バイト列を別のTStringStReamに書き込む
LStrStreamDst.Position := 0;
LStrStreamDst.WriteBuffer(LPByte^, LSize);
//TStringStreamに格納されているデータの確認
//文字列としてストリームのデータをAnsiString型の文字列にコピー
SetLength(LTextDst, LSize);
LStrStreamDst.Position := 0;
LStrStreamDst.ReadBuffer(LTextDst[1], LSize);
Memo1.Lines.Add('TStringStream と PByte 型バイト列の読み書き');
Memo1.Lines.Add(string(LTextDst));
finally
FreeMem(LPByte);
end;
finally
FreeAndNil(LStrStreamSrc);
FreeAndNil(LStrStreamDst);
end;
end;
03_PByte 型バイト列とバイト配列のデータとの変換 |
PByte 型で操作するバイト列の値と,バイト配列データとの相互変換のサンプルです.テスト用のバイト値として,1 バイトの文字である AnsiString 型の ASCII 文字を使用しています.
文字列を PByte 型でバイト列をメモリに格納した後,そのバイト列を Move 関数を使用してバイト配列にコピーします.バイト配列に格納したデータを Move 関数で文字列に変換して表示します.動的なバイト配列と静的なバイト配列の両方でテストしています,
TMemo にデータを表示する際,string で型キャストしています.これは「W1057 文字列の暗黙のキャスト ('AnsiString' から 'string')」という警告を表示しないようにするためです. |
|
図8
PByte 型のバイト列とバイト配列データとの変換
|
|
図9
PByte 型のバイト列とバイト配列データとの変換
|
//=============================================================================
// PByte型のバイト列とTBytes型バイト配列データのコピー操作
//
// TBytesはバイト型の動的配列
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LTextSrc : AnsiString;
LTextDst : AnsiString;
LBytes : TBytes;
LPByte : PByte;
LSize : Integer;
begin
Memo1.Lines.Clear;
//テスト文字列(バイト文字列)
LTextSrc :='ABCDEFG';
//バイト列データ用のメモリ領域を確保
LSize := Length(LTextSrc);
LPByte := AllocMem(LSize);
try
//文字列をバイト列データとしてメモリに格納
Move(LTextSrc[1], LPByte^, LSize);
//バイト配列のサイズを設定してメモリのデータをバイト配列にコピー
SetLength(LBytes, LSize);
Move(LPByte^, LBytes[0], LSize);
//出力先の文字列のサイズを設定してバイト配列のデータをコピー
LSize := Length(LBytes);
SetLength(LTextDst, LSize);
Move(LBytes[0], LTextDst[1], LSize);
//結果の表示
Memo1.Lines.Add('PByte 型バイト列と動的バイト配列データの変換');
Memo1.Lines.Add(string(LTextDst));
finally
FreeMem(LPByte);
end;
end;
//=============================================================================
// PByte型のバイト列データとTBytes型データのコピー操作
//
// TByteArrayはバイト型の静的配列
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LTextSrc : AnsiString;
LTextDst : AnsiString;
LBytes : TByteArray;
LPByte : PByte;
LSize : Integer;
begin
Memo1.Lines.Clear;
//テスト文字列(バイト文字列)
LTextSrc :='ABCDEFG';
//バイト列データ用のメモリ領域を確保
LSize := Length(LTextSrc);
LPByte := AllocMem(LSize);
try
//文字列をバイト列としてメモリに格納
Move(LTextSrc[1], LPByte^, LSize);
//バイト配列のサイズを設定してメモリのデータをバイト配列にコピー
Move(LPByte^, LBytes[0], LSize);
//出力先の文字列のサイズを設定してバイト配列のデータをコピー
LSize := Length(LBytes);
SetLength(LTextDst, LSize);
Move(LBytes[0], LTextDst[1], LSize);
//結果の表示
Memo1.Lines.Add('PByte 型バイト列と静的バイト配列データの変換');
Memo1.Lines.Add(LTextDst);
finally
FreeMem(LPByte);
end;
end;
04_PByte 型バイト列と Char 型の文字配列データとの変換 |
PByte 型のバイト列の値を Char 型の文字配列のデータに変換するサンプルです.Char 型の文字配列のデータを PByte 型のバイト列にする具体的なコードは掲載していませんが,Move 関数の引数を逆にすれば変換できます.
文字列をバイト列の値としてメモリに格納した後,そのバイト列を Move 関数で Char 型の文字配列にコピーします.Char 型の動的配列と Char 型の静的配列の両方でテストしています,
Char 型の文字配列に格納されているデータを文字列として取り出すには,Null 終端の文字が必要です.本サンプルでは Char 型の要素数 (サイズ) を設定する時に追加しています. |
|
図10
PByte 型バイト列を Char 型の文字配列にコピー
|
|
図11
PByte 型バイト列を Char 型の文字配列にコピー
|
//=============================================================================
// PByte型のバイト列をChar型の文字配列のデータとしてコピー
//
// テスト用の文字列をPByte型のバイト列として格納
// そのバイト列をChar型の文字配列にコピーする
//
// TCharArrayはChar型の動的配列
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LText : string;
LByteSize : Integer;
LPByte : PByte;
LCharArrDst : TCharArray;
LTextDst : string;
begin
Memo1.Lines.Clear;
//テスト用文字列
LText := 'PByte 型のバイト列を Char 型の文字配列に' + sLineBreak
+ 'Char 型の動的配列の場合';
//バイト列のサイズを設定して
//String型の文字列をバイト列としてメモリに格納
LByteSize := Length(LText) * SizeOf(Char);
LPByte := AllocMem(LByteSize);
try
Move(LText[1], LPByte^, LByteSize);
//テスト用バイト列作成終了
//PByte型のバイト列をChar型の文字配列にコピー
//Null終端分を含めたサイズが必要
SetLength(LCharArrDst, LByteSize div SizeOf(Char) + SizeOf(Char));
Move(LPByte^, LCharArrDst[0], LByteSize);
//結果の表示
LTextDst := PChar(@LCharArrDst[0]);
Memo1.Lines.Add(LTextDst);
finally
Freemem(LPByte);
end;
end;
//=============================================================================
// PByte型のバイト列をChar型の文字配列のデータとしてコピー
//
// テスト用の文字列をPByte型のバイト列として格納
// そのバイト列をChar型の文字配列にコピーする
//
// Char型の文字配列が静的配列の例
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LText : string;
LByteSize : Integer;
LPByte : PByte;
LCharArrDst : array [0..99] of Char;
LTextDst : string;
begin
Memo1.Lines.Clear;
//テスト用文字列
LText := 'PByte 型のバイト列を Char 型の文字配列に' + sLineBreak
+ 'Char 型の静的配列の場合';
//バイト列のサイズを設定して
//String型の文字列をバイト列としてメモリに格納
LByteSize := Length(LText) * SizeOf(Char);
LPByte := AllocMem(LByteSize);
try
Move(LText[1], LPByte^, LByteSize);
//テスト用バイト列作成終了
//PByte型のバイト列をChar型の文字配列にコピー
FillChar(LCharArrDst, SizeOf(LCharArrDst), #0);
Move(LPByte^, LCharArrDst[0], LByteSize);
//結果の表示
LTextDst := LCharArrDst;
Memo1.Lines.Add(LTextDst);
finally
Freemem(LPByte);
end;
end;
05_PByte 型バイト列と String 型の文字列との変換 |
PByte 型のバイト列と String 型の文字列との相互変換のサンプルです.
この変換は既にこれまでのサンプルで使用していますが,再掲しておきます. |
|
図12
PByte 型バイト列と String 型との相互変換 |
//=============================================================================
// PByte型のバイト列をString型の文字列のデータにする例
//
// テスト用の文字列をPByte型のバイト列として格納
// そのバイト列をString型の文字列にコピーする
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LText : string;
LTextDst : string;
LPByte : PByte;
LByteSize : Integer;
begin
Memo1.Lines.Clear;
//テスト用文字列
LText := 'PByte 型のバイト列を String 型の文字列に';
//バイト列のサイズを設定して
//String型の文字列をバイト列としてメモリに格納
LByteSize := Length(LText) * SizeOf(Char);
LPByte := AllocMem(LByteSize);
try
Move(LText[1], LPByte^, LByteSize);
//テスト用バイト列作成終了
//文字列のサイズを設定してPByte型バイト列をString型の文字列に代入
SetLength(LTextDst, LByteSize div SizeOf(Char));
Move(LPByte^, LTextDst[1], LByteSize);
//結果の表示
Memo1.Lines.Add(LTextDst);
finally
Freemem(LPByte);
end;
end;
06_PByte 型バイト列と PChar 型の文字列との変換 |
PByte 型バイト列と PChar 型の文字列との相互変換のサンプルです.
まず PChar 型の文字列を Move 関数を使用して,PByte 型のバイト列としてメモリに格納します.そのバイト列を Move 関数を使用して別の PChar 型の文字列に変換します. |
|
図13
PByte 型バイト列と PChar 型の文字列との変換 |
//=============================================================================
// PByte型のバイト列をPChar型の文字列のデータにする例
//
// テスト用の文字列をPByte型のバイト列として格納
// そのバイト列をPChar型の文字列にコピーする
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LPChar : PChar;
LByteSize : Integer;
LPByte : PByte;
LPCharDst : PChar;
begin
Memo1.Lines.Clear;
//テスト用文字列
LPChar := 'PByte 型のバイト列を PChar 型の文字列に';
//バイト列のサイズを設定して
//PChar型の文字列をバイト列としてメモリに格納
LByteSize := StrLen(LPChar) * SizeOf(Char);
LPByte := AllocMem(LByteSize);
try
Move(LPChar^, LPByte^, LByteSize);
//テスト用バイト列作成終了
//PByte型バイト列をPChar型の文字列に代入
//Null終端の文字分を含めたバイト数を確保
LPCharDst := AllocMem(LByteSize + SizeOf(Char));
try
Move(LPByte^, LPCharDst^, LByteSize);
//結果の表示
Memo1.Lines.Add(LPCharDst);
finally
FreeMem(LPCharDst);
end;
finally
Freemem(LPByte);
end;
end;
PByte 型バイト列と数値との相互変換のサンプルです.
まず数値を Move 関数を使用して,PByte 型のバイト列としてメモリに格納します.そのバイト列を Move 関数を使用して別の数値の変数のデータとしてコピーします.
整数型と実数型の数値でテストしています. |
|
図14
PByte 型バイト列と数値との変換
|
|
図15
Byte 型バイト列と数値との変換
|
//=============================================================================
// PByte型のバイト列と数値の変換
//
// テスト用の数値をPByte型のバイト列としてメモリに格納
// そのバイト列をInteger型の数値として取り出す
//=============================================================================
procedure TForm1.Button1Click(Sender: TObject);
var
LIntegerSrc : Integer;
LIntegerDst : Integer;
LPByte : PByte;
LByteSize : Integer;
begin
Memo1.Lines.Clear;
//テスト用の数値
LIntegerSrc := 123456;
//バイト列のサイズを設定して数値をバイト列に格納
LByteSize := SizeOf(Integer);
LPByte := AllocMem(LByteSize);
try
Move(LIntegerSrc, LPByte^, LByteSize);
//バイト列の値を数値の変数にコピー
Move(LPByte^, LIntegerDst, SizeOf(Integer));
//結果の表示
Memo1.Lines.Add('PByte 型のバイト列と整数値の変換');
Memo1.Lines.Add(IntToStr(LIntegerDst));
finally
FreeMem(LPByte);
end;
end;
//=============================================================================
// PByte型のバイト列と数値の変換
//
// テスト用の数値をPByte型のバイト列としてメモリに格納
// そのバイトデータをDouble型の数値として取り出す
//=============================================================================
procedure TForm1.Button2Click(Sender: TObject);
var
LDoubleSrc : Double;
LDoubleDst : Double;
LPByte : PByte;
LByteSize : Integer;
begin
Memo1.Lines.Clear;
//テスト用の数値
LDoubleSrc := 1.23456E+12;;
//バイト列のサイズを設定して数値をバイト列に格納
LByteSize := SizeOf(Double);
LPByte := AllocMem(LByteSize);
try
Move(LDoubleSrc, LPByte^, LByteSize);
//バイト列を数値の変数にコピー
Move(LPByte^, LDoubleDst, SizeOf(Double));
//結果の表示
Memo1.Lines.Add('PByte 型のバイト列と実数値の変換');
Memo1.Lines.Add(FormatFloat('0.000E+00', LDoubleDst));
finally
FreeMem(LPByte);
end;
end;
|