歴史的に(おそらくその一部を書き換えることによって)、それは反対でした。プロトタイプの初期C(おそらくBCPL)を実行している1970年代初期の最初のコンピューター(おそらくPDP-11)には、MMUもメモリー保護もありません(ほとんどの古いIBM / 360メインフレームに存在していました)。(リテラル文字列またはマシンコードを扱うものを含む)メモリのすべてのバイトが誤ったプログラムによって上書きされる可能性がありますので、(一部を変更するプログラムを想像する中のprintf(3)フォーマット文字列を)。したがって、リテラル文字列と定数は書き込み可能です。%
/
1975年にティーンエイジャーとして、私は、メモリ保護せずに、古い1960年代の時代のコンピュータでは、パリのパレ・デ・ラ・DECOUVERTE博物館でコーディング:/ 1620 IBMは、あなたが数十を入力しなければならなかったので、あなたはキーボードを通して初期化することができ-whichのみコアメモリを持っていましたパンチテープの初期プログラムを読み取るための数字; CAB / 500には磁気ドラムメモリがありました。ドラムの近くの機械的なスイッチを介していくつかのトラックの書き込みを無効にすることができます。
後に、コンピューターは何らかのメモリ保護を備えた何らかの形式のメモリ管理ユニット(MMU)を取得しました。CPUが何らかのメモリを上書きすることを禁止するデバイスがありました。そのため、いくつかのメモリセグメント、特にコードセグメント(.text
セグメント)は読み取り専用になりました(ディスクからそれらをロードしたオペレーティングシステムを除く)。コンパイラとリンカがそのコードセグメントにリテラル文字列を置くのは自然であり、リテラル文字列は読み取り専用になりました。あなたのプログラムがそれらを上書きしようとしたとき、それは悪い、未定義の振る舞いでした。また、仮想メモリに読み取り専用コードセグメントがあると、大きな利点が得られます。同じプログラムを実行する複数のプロセスが同じRAM(物理メモリを共有します。ページ)そのコードセグメント(Linuxのmmap(2)のMAP_SHARED
フラグを参照)。
現在、安価なマイクロコントローラには、読み取り専用メモリ(フラッシュやROMなど)があり、コード(およびリテラル文字列やその他の定数)がそこに保持されています。また、実際のマイクロプロセッサ(タブレット、ラップトップ、デスクトップなど)には、仮想メモリとページングに使用される洗練されたメモリ管理ユニットとキャッシュ機構があります。コードセグメントだから、実行可能なプログラム(例えば中ELFが)によって、読み取り専用としてマップされたメモリ、共有可能、および実行可能なセグメント(あるのmmap(2)またははexecve(2) Linux上;ところで、あなたはに指示を与えることができるLDあなたが本当にしたい場合は、書き込み可能なコードセグメントを取得します)。それを書くか乱用するのは一般にセグメンテーション違反です。
したがって、C標準はバロックです。法的に(歴史的な理由のみ)、リテラル文字列はconst char[]
配列ではなく、char[]
上書きが禁止されている配列のみです。
ところで、文字列リテラルの上書きを許可する現在の言語はほとんどありません(歴史的に-ひどく-書き込み可能なリテラル文字列を持っていたOcamlでさえ、最近4.02でその動作を変更し、現在は読み取り専用の文字列を持っています)。
現在のCコンパイラは、最後の5バイト(終端のnullバイトを含む)を最適化し"ions"
、"expressions"
共有することができます。
ファイル内のCコードをコンパイルしようfoo.c
とgcc -O -fverbose-asm -S foo.c
生成されたアセンブラファイル内のルックfoo.s
でGCC
最後に、意味論 Cのは複雑で十分です(詳細読みCompCert&FRAMA-C 、それを捕獲しようとしている)及び(およびより少ないと、プログラムが弱く、さらには安全性の低いながら書き込み可能な定数リテラル文字列は、それがさらに難解になるだろう追加します定義された動作)、したがって、将来のC標準が書き込み可能なリテラル文字列を受け入れることはほとんどありません。おそらく反対に、彼らはconst char[]
道徳的にすべきであるようにそれらを配列にするでしょう。
また、多くの理由で、可変データは、定数データよりもコンピューターによる処理(キャッシュの一貫性)、開発者によるコード化、理解が難しいことに注意してください。したがって、ほとんどのデータ(特にリテラル文字列)を不変に保つことが望ましいです。関数型プログラミングの パラダイムについて詳しく読んでください。
IBM / 7094の古いFortran77の時代には、バグが定数を変更することさえありました。もしあなたがたまたま引数を2に渡して参照を変更したCALL FOO(1)
場合FOO
、実装は1の他の出現を2に変更したかもしれません。いたずらなバグ、見つけるのはかなり難しい。