Pascal文字列
Pascal文字列(Pascal string)は配列の先頭に文字列長を埋め込んだ特殊な文字列です。
// パスカル文字列
char pstr[] = {3, 'a', 'b', 'c'};
// ヌル終端文字列
char cstr[] = {'a', 'b', 'c', '\0'};
このように文字列の長さが直接データ内に埋め込まれているという特徴があります。
文字列長の計算コストが低い
通常のC言語文字列と違い、文字列長を求める際の計算量が非常に小さくなるという特徴があります。
// パスカル文字列
char pstr[] = {3, 'a', 'b', 'c'};
unsigned char size = pstr[0]; // 値取得のコストのみ
// ヌル終端文字列
char cstr[] = {'a', 'b', 'c', '\0'};
size_t size = strlen(cstr); // 計算量は文字列長に依存
ナル文字を含めることが出来る
また文字列にナル文字(\0
, 0x00
)を含めることが出来るという特徴もあります。
unsigned char utf16[] = {6, 0xFF, 0xFE, 0x61, 0x00, 0x62, 0x00};
C言語文字列との互換性がない
標準のC言語ライブラリはPascal文字列に対応していないため、文字列処理は自前で行う必要があります。
char pstr[] = {3, 'a', 'b', 'c'};
size_t size = (unsigned char)pstr[0];
fwrite(1 + pstr, 1, size, stdout); // "abc"
ただし例外的に、Pascal文字列の終端に仮想的なナル文字を埋め込むことで、C言語文字列との互換性を持たせることも可能です。
char pstr[] = {3, 'a', 'b', 'c', '\0'};
puts(pstr + 1); // "abc"
文字列長に制限がある
配列先頭に埋め込める文字列長はchar型のビット数(8bit)に依存するという問題があります。これはつまりPascal文字列は事実上255文字までの文字列しか扱えないということでもあります。
Pascal文字列リテラルを実現する拡張機能
コンパイラオプション-fpascal-strings
を用いると、文字列リテラル内で\p
という特殊なエスケープシーケンスが利用出来るようになり、これにより文字列長の自動計算が行われるようになります。
// clang main.c -fpascal-strings
const unsigned char pstr[] = "\pabc"; // {0x03, 'a', 'b', 'c', '\0'}
puts(pstr); // "\x03abc"
printf("%ld", sizeof(pstr)); // 5 (ナル文字含む)
printf("%ld", strlen(pstr)); // 4 (先頭の符号も含むため)
printf("%ld", strlen(pstr + 1)); // 3
printf("%d", (unsigned char)*pstr); // 3 (文字列長)