各種文字列の実際

ShortString (Pascal文字列)
 ShortString...伝統的なPascal文字列の構造は以下のようになっています。

要素数
(byte)
文字列
(文字構成要素: Char/AnsiChar)
S[0] S[1] S[2] S[n]

 "要素数"は文字列を構成する文字構成要素の数...つまり文字列長です。 ShortStringに於いて'ABC'のような文字列は、

要素数
(byte)
文字列
(文字構成要素: Char/AnsiChar)
3 'A' 'B' 'C'

 このように格納されています。要素数はbyteの範囲でしか格納できないので、ShortString(Pascal文字列)の最大長は255文字となります。 また、ShortString(Pascal文字列)に於いて"Byte(S[0])"は"Length(S)"と同義になります。

String/AnsiString (長い文字列) #1
 Delphi2007またはそれ以前のStringの構造は以下のようになっています。

参照カウンタ
(LongInt)
要素数
(LongInt)
文字列
(文字構成要素: Char/AnsiChar)
Null
(8bit)
S[1] S[2] S[n]

 "参照カウンタ"はその名の通り、この文字列の実体が変数によって参照されている数です。参照カウンタが0になると文字列が確保していた領域が破棄されます。また、参照カウンタは"-1"を指す事があります。これは定数や、定数を代入された変数です。

// D2007(またはそれ以前)用
var
  S1, S2: AnsiString;
  function ReferenceCount(const S: AnsiString): LongInt;
  begin
    result := LongInt(S);
    if result <> 0 then
      result := PLongInt(result - SizeOf(LongInt) - SizeOf(LongInt))^;
  end;
  function ElementCount(const S: AnsiString): LongInt;
  begin
    result := LongInt(S);
    if result <> 0 then
      result := PLongInt(result - SizeOf(LongInt))^;
  end;
begin
  S1 := 'A';
  ShowMessage(Format('Reference=%d : Elements=%d', [ReferenceCount(S1), ElementCount(S1)]));
  S2 := S1 + 'B';
  ShowMessage(Format('Reference=%d : Elements=%d', [ReferenceCount(S2), ElementCount(S2)]));
end;

 このようなコードで検証する事が可能です。なお、 Delphi2007(またはそれ以前)のUTF8Stringも全く同一の構造となっています("UTF8String = type AnsiString;")。

PChar (ヌルで終わる文字列)
 C/C++でお馴染みPCharです。正確には文字列型ではありません。文字配列へのポインタです。

文字列
(文字構成要素: Char/AnsiChar)
S[0] S[1] S[n-1] Null

 文字列の"要素数"を持たないため、8bit-Null(0x00)で文字列を終端する必要があります。

WideString
 WideStringです。

要素数
(LongInt)
文字列
(文字構成要素: WideChar)
Null
(16bit)
S[1] S[2] S[n]

 要素数はバイト換算です。'ABC'の要素数は"6"となります。WideString型はCOMで使われるBSTRと互換性があります。

PWideChar (ヌルで終わる文字列)
 PWideCharです。正確には文字列型ではありません。文字配列へのポインタです。

文字列
(文字構成要素: WideChar)
S[0] S[1] S[n-1] Null

 PChar同様ですが、終端は16bit-Null(0x0000)です。

UCS4String
 UCS4Stringです。正確には文字列型ではありません。LongWordの動的配列です。

参照カウンタ
(LongInt)
要素数
(LongInt)
文字列
(文字構成要素: LongWord)
S[0] S[1] S[n-1] Null

 Delphiの他の文字列型とは性格が違います。添え字は"0"から始まり、終端として32bit-Null(0x00000000)が必要です。PCharやPWideCharに近い構造です。しかしながら、動的配列なのでPCharやPWideCharと違いメモリ確保の必要はありません。

UnicodeString/AnsiString (長い文字列) #2
 Delphi2009のUnicodeString/AnsiStringの構造は以下のようになっています。

コードページ
(WORD)
要素サイズ
(WORD)
参照カウンタ
(LongInt)
要素数
(LongInt)
文字列
(文字構成要素: 任意)
Null
(サイズは要素サイズに依存)
S[1] S[2] S[n]

 Delphi2007またはそれ以前のAnsiStringの構造に"コードページ"と"要素サイズ"を付加したような構造になっています。コードページはStringCodePage()、要素サイズはStringElementSize()、参照カウンタはStringRefCount()で取得する事が可能です。

 AnsiStringに'ABC'を代入した時の状態は以下のようになります。

コードページ
(WORD)
要素サイズ
(WORD)
参照カウンタ
(LongInt)
要素数
(LongInt)
文字列
(文字構成要素: AnsiChar)
Null
(8bit)
932 1 -1 3 'A' 'B' 'C'

 UnicodeStringに'ABC'を代入した時の状態は以下のようになります。要素数はWideStringと違い、文字数(文字構成要素数)となっています。

コードページ
(WORD)
要素サイズ
(WORD)
参照カウンタ
(LongInt)
要素数
(LongInt)
文字列
(文字構成要素: Char/WideChar)
Null
(16bit)
1200 2 -1 3 'A' 'B' 'C'

 以下のようなコードで検証する事が可能です。

// D2009用
var
  A: AnsiString;
  U: UnicodeString;
  function ElementCount(const S: RawbyteString): LongInt; overload;
  begin
    result := LongInt(S);
    if result <> 0 then
      result := PLongInt(result - SizeOf(LongInt))^;
  end;
  function ElementCount(const S: UnicodeString): LongInt; overload;
  begin
    result := LongInt(S);
    if result <> 0 then
      result := PLongInt(result - SizeOf(LongInt))^;
  end;
begin
  A := 'ABC';
  ShowMessage(Format('CodePage=%d : ElementSize=%d : Reference=%d : ElementCount=%d',
                     [StringCodePage(A), StringElementSize(A), StringRefCount(A), ElementCount(A)]));
  U := 'ABC';
  ShowMessage(Format('CodePage=%d : ElementSize=%d : Reference=%d : ElementCount=%d',
                     [StringCodePage(U), StringElementSize(U), StringRefCount(U), ElementCount(U)]));
end;

総括
 文字列の領域が文字列として一般的にアクセスされる領域で、変数へのポインタは通常この文字列の先頭を指します。ソースコードでS[1]を渡しているものをよく見かけるのはそういう事です。また、文字列の中にNullが含まれる文字列型はヌルターミネートとなり、文字列中にNullを含める事ができません。


 BACK