[解決済み】NULL終端文字列の根拠は何ですか?
質問
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言語の開発
関連
-
[解決済み] エラーが発生する。ISO C++は型を持たない宣言を禁じています。
-
[解決済み] error: 'if' の前に unqualified-id を期待した。
-
[解決済み】C++エラー:の初期化に一致するコンストラクタがありません。
-
[解決済み] 既に.objで定義されている-二重包含はない
-
[解決済み】cc1plus:エラー:g++で認識されないコマンドラインオプション"-std=c++11"
-
[解決済み】なぜ、サイズ8の初期化されていない値を使用するのでしょうか?
-
[解決済み] SQLiteのINSERT/per-secondのパフォーマンスを向上させる
-
[解決済み] プログラム終了前にmallocの後にfreeをしないと本当に何が起こるのか?
-
[解決済み] Pythonで文字列が繰り返されるかどうかを判断するにはどうすればよいですか?
-
[解決済み] Intel CPU の _mm_popcnt_u64 で、32 ビットのループカウンターを 64 ビットに置き換えると、パフォーマンスが著しく低下します。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C++エラーです。"配列は中括弧で囲まれたイニシャライザーで初期化する必要がある"
-
[解決済み] string does not name a type Errorが発生するのはなぜですか?
-
[解決済み】Cygwin Make bash コマンドが見つかりません。
-
[解決済み】デバッグアサーションに失敗しました。C++のベクトル添え字が範囲外
-
[解決済み】オブジェクト引数のない非静的メンバ関数の呼び出し コンパイラーエラー
-
[解決済み] 非静的データメンバの無効な使用
-
[解決済み] gdbを使用してもデバッグシンボルが見つからない
-
[解決済み】演算子のオーバーロード C++; <<操作のパラメータが多すぎる
-
[解決済み] スタックアロケーションにより初期化されていない値が作成された
-
[解決済み】c++で.txtファイルから2次元の配列に読み込む