27

私がそうするなら、私はCでそれを聞いた

char *s = "hello world". 

「helloworld」は実際には読み取り専用メモリに格納されています。

読み取り専用メモリについてはあまり明確ではありません。説明は何ですか?これは、コンパイラにそのセクションに書き込まないように指示するコンパイラへのフラグのようなものですか?

4

7 に答える 7

37

これはC言語の機能ではなく、コンパイラー/リンカーとオペレーティングシステムが連携して動作する機能です。

このようなコードをコンパイルすると、次のようになります。

  • コンパイラは、文字列を読み取り専用のデータセクションに配置します。

  • リンカは、このような読み取り専用セクションのすべてのデータを収集し、それらを単一のセグメントに配置します。このセグメントは実行可能ファイルに存在し、「読み取り専用」属性のフラグが付けられます。

  • 次に、オペレーティングシステムの実行可能ローダーが登場します。実行可能ファイルをロードします(または、より正確にはメモリにマップします)。これが完了すると、ローダーはセクションをウォークし、各セグメントのアクセス許可を設定します。読み取り専用のデータセグメントの場合、コード実行および書き込みアクセスが無効になる可能性があります。コード(たとえば、関数)は実行権限を取得しますが、書き込みアクセス権は取得しません。静的変数などの通常のデータは、読み取りおよび書き込みアクセスなどを取得します...

これが、最新のオペレーティングシステムが行う方法です。

言ったように、それはC言語の機能ではありません。たとえば、DOSで同じ問題をコンパイルすると、プログラムは実行されますが、DOSローダーは読み取り専用セクションを認識しないため、書き込み保護はできません。

于 2009-11-10T00:34:08.037 に答える
6

実行可能ファイルには、グローバル変数を含む.dataセクションと、実際のマシンコードを含む.textセクションの2つの部分が含まれています。

文字列は.dataセクションに配置されます。Cが「Helloworld」を検出すると、実行可能ファイル自体に文字列「Hello world」を挿入し、プログラム内の「Helloworld」のインスタンスをその文字列がロードされるアドレスに置き換えます。

そうは言っても、なぜそれが読み取り専用であるのかはわかりません。理論的には、プログラムはそれ自体のメモリを変更できるはずです。

于 2009-11-10T00:32:23.570 に答える
4

真の読み取り専用メモリは、OSのメモリサブシステムによって実装されます。OSは、特定のページを読み取り専用としてマークできます。

バイナリでは、コンパイラは、実行可能ファイルのどの部分を読み取り専用メモリページと読み取り/書き込みメモリページに配置するかをOSに指示できます。

于 2009-11-10T00:32:04.600 に答える
3

Linuxでこれを行う方法の例は、Mark Mitchell、Jeffrey Olham、およびAlexSamuelによるAdvancedLinuxProgrammingの179ページにあります。

于 2009-11-10T00:37:55.553 に答える
3

あなたが書くときchar s[10]="sneha"; オブジェクトファイルに10バイトのストレージスペース(メモリではなく、プログラムの実行時にのみメモリが表示されます)を割り当てています。これは、(コンパイル時の)メモリの静的割り当てです。

しかし、あなたが書くとき、あなたchar *s="sneha";は保存するためにどんな記憶スペースも割り当てていません"sneha"。読み取り専用セクションに保存されます。ただし、ポインタsは、宣言されている場所に基づいて異なるセクションに格納されます。しかし、それは読み取り専用データを指してい"sneha"ます。したがって、それに書き込もうとすると、セグメンテーション違反が発生します。

例えば:

char *s = "sneha";
s[1] = 'N'; 
printf("%s",s);  // you expecting output sNeha, 
                 // but you get a seg fault since it is READ ONLY DATA 
于 2016-07-08T20:43:28.587 に答える
1

他の人が述べているように、定数文字列の内容が読み取り専用メモリに格納されるかどうかは、オペレーティングシステム、コンパイラ、およびチップアーキテクチャによって決まります。

より正確には、C標準は、引用符で囲まれた文字列が「const char []」型であると見なされることを指定しています(またはその趣旨の単語、私は手元に標準を持っていません)。

このような文字列の内容を変更しようとするコードは、未定義の動作を呼び出しています。つまり、その時点で文字通り何でも起こり得ることを意味し、コンパイラのプロバイダーは、起こり得ることを文書化する必要さえありません。

実際には、これは、移植性を求めているCまたはC ++プログラムは、定数文字列の変更を回避する必要があることを意味します。

一般に、コンパイラーでは「const」変数の内容を変更できないため、ほとんどの場合、「const」は「読み取り専用」を意味すると見なすことができます。残念ながら、主に歴史的な理由から、char*とconstchar*には特別な例外があります。つまり、次のようなコードです。

char *x = "Hello, World";
*x = 'h';

未定義の動作を呼び出しても、エラーや警告なしでコンパイルされます。

于 2009-11-10T01:19:26.713 に答える
1

あなたは次のようなことを試すことができます

s[4] = '0';

電話をかけたときに「hellow0rld」と表示されるかどうかを確認します

puts(s);

即時のセグメンテーション違反またはデータ実行防止例外が発生する場合は、おそらく読み取り専用です。(システムがそれを回避できるのであれば、それは良い考えではありません。)

于 2009-11-10T00:38:43.537 に答える