1. ホーム
  2. c++

[解決済み】NULL終端文字列の根拠は何ですか?

2022-03-30 11:31:26

質問

CとC++が大好きな私ですが、NULL終端文字列の選択には首を傾げざるを得ません。

  • 長さの接頭辞を持つ(つまりパスカル)文字列はC以前から存在していた
  • 長さ接頭辞付き文字列は、長さのルックアップを一定時間可能にすることで、いくつかのアルゴリズムを高速化します。
  • 長さプリフィクスされた文字列は、バッファオーバーランエラーの発生をより困難にする。
  • 32ビットマシンでも、文字列が利用可能なメモリのサイズになるようにすれば、長さの接頭辞の付いた文字列は、ヌル終端文字列よりも3バイトだけ広くなります。16ビットマシンでは、これは1バイトになります。64ビットマシンでは、4GBが妥当な文字列長の制限ですが、マシンワードのサイズに拡張するとしても、64ビットマシンには通常十分なメモリがあるので、7バイトの余分はある種の空論となります。オリジナルのC標準は、(メモリの点で)非常に貧弱なマシンのために書かれたことは知っていますが、効率性の議論には納得がいきません。
  • 他のほとんどすべての言語(Perl、Pascal、Python、Java、C#など)は、長さの接頭辞のついた文字列を使用します。これらの言語は、文字列操作のベンチマークでは通常 C に勝ります。なぜなら、これらの言語は文字列の扱いがより効率的だからです。
  • C++は、この点を std::basic_string テンプレートがありますが、ヌル文字で終端する文字列を期待するプレーンな文字配列はまだ広く存在しています。また、ヒープ割り当てが必要なため、不完全です。
  • NULL終端文字列は、文字列中に存在し得ない文字(すなわちNULL)を予約しなければなりませんが、長さ優先の文字列は埋め込まれたNULLを含むことができます。

これらのうちいくつかは、C言語よりも最近になって明らかになったものなので、C言語が知らなかったというのも納得がいきます。しかし、いくつかはCが登場するずっと以前から平易なものでした。なぜ、明らかに優れた長さのプリフィックスではなく、ヌル終端文字列が選ばれたのでしょうか。

EDIT : という要望がありましたので ファクト (というのも、上記の私の効率性についての指摘は、いくつかの事柄に起因するものだからです。

  • NULL終端文字列を使用したConcatは、O(n + m)の時間複雑性を必要とします。長さのプリフィクスはしばしばO(m)で済みます。
  • NULL終端文字列を使用した長さの計算にはO(n)の時間計算が必要です。長さのプリフィクスはO(1)です。
  • Lengthとconcatは、圧倒的に一般的な文字列操作です。ヌル文字で終端する文字列の方が効率的な場合もいくつかありますが、その頻度はかなり低くなります。

以下の回答から、ヌル文字で終端する文字列の方が効率的な場合があることがわかります。

  • 文字列の先頭を切り取って、何らかのメソッドに渡す必要がある場合。長さの接頭辞はおそらくアラインメント規則に従う必要があるため、元の文字列を破棄することができるとしても、長さの接頭辞ではこれを一定時間内に行うことは実際不可能です。
  • 文字列を1文字ずつループしているだけの場合、CPUのレジスタを節約できるかもしれません。これは、文字列を動的に割り当てていない場合にのみ有効であることに注意してください (その場合、文字列を解放する必要があるため、保存した CPU レジスタを使用して malloc などから取得したポインタを保持する必要があるからです)。

上記のどれもが、lengthとconcatほど一般的ではありません。

以下の回答でもう一つ断言されていることがあります。

  • 文字列の末尾を切り取る必要があります

しかし、これは誤りです。ヌル文字で終端する文字列と長さのあるプリフィックス文字列では、同じ時間です。(ヌル文字で終端する文字列は新しい終端の位置にヌルを付けるだけで、長さの接頭辞は接頭辞から減算するだけです)。

解決方法は?

からの 馬の口

BCPL、B、Cのいずれもサポートされていない 文字データを 言語では、文字列は 整数のベクトルと同じで 一般的なルールをいくつかの 規則があります。BCPLとBの両方において 文字列リテラルのアドレスは で初期化された静的領域。 文字列の文字を セルになります。BCPLでは、最初のパックされたバイト の文字数が含まれます。 Bの場合、カウントはありません。 で終端し、文字列は という特殊文字があり、Bでは *e . この変更は、一部で行われました。 の長さの制限を回避するためです。 を保持することによって生じる文字列の 8ビットまたは9ビットスロットのカウントと カウントを維持するため は、経験上、あまり良くないと思います。 ターミネーターを使うより便利です。

<サブ デニス・M・リッチー C言語の開発