2

定数リテラル get が (SO から) プログラムのデータ セグメントに配置され、読み取り専用であるため、" s[0] = 'a' " という行でエラーが発生することがわかりました。その行のコメントを外して実行しました。しかし、MS VS のメモリ ウィンドウを調べたところ、変数はすべてメモリ内にまとめて配置されています。彼ら(コンパイラ)が「s」への読み取り専用アクセスをどのように強制するかについて興味がありますか?

#include <iostream>

int main(void)
{
      char *s = "1023";
      char s_arr[] = "4237";
      char *d = "5067";
      char s_arr_1[] = "9999";
      char *e = "6789";
      printf("%c\n", s[0]);
//      s[0] = 'a'; This line would error out since s should point to data segment of the program
      printf("%s\n", s);
      system ("pause");
}

0x002E54F4  31 30 32 33 00 00 00 00 34 32 33 37 00 00 00 00  1023....4237....
0x002E5504  35 30 36 37 00 00 00 00 39 39 39 39 00 00 00 00  5067....9999....
0x002E5514  36 37 38 39 00 00 00 00 25 63 0a 00 25 73 0a 00  6789....%c..%s..
0x002E5524  70 61 75 73 65 00 00 00 00 00 00 00 43 00 3a 00  pause.......C.:.

編集 1: s_arr (スタック領域に配置する必要があります) に格納されている値を更新して、文字列定数に隣接して配置されていることを明確にします。

編集 2: ページに基づく ro/rw アクセスに関する回答を見ているので、ここではアドレス .. 0x...4f4 は rw 0x...4fc はroで、0x...504 は rw です。彼らはどのようにしてこの粒度を達成するのでしょうか? また、各ページは最小 4kb である可能性があるため、0x4fb は前の ro ページの最後のアドレスである可能性があると主張できます。しかし、いくつかの変数を追加して、それらがすべてメモリ内に連続して配置され、粒度が 8 バイトごとであることを示しました。あなたが言ったように、ページは4kレベルなので、

4

3 に答える 3

7

あなたの例が変更不可能なメモリの隣に変更可能なメモリを示しているとあなたが思った理由はわかりません。あなたが話している「粒度」は何ですか?あなたのメモリダンプはそのようなものを示していません。

"4237"メモリ ダンプに表示される文字列s_arr. の初期化子として使用された読み取り専用の文字列リテラルがあること"4237"がわかります。そのイニシャライザは にコピーされました。一方、actualは別の場所 (スタック内) に存在し、完全に変更可能です。(初期値として) も含まれていますが、それは完全に異なるであり、メモリ ダンプには表示されません。プログラムにアドレスを出力するように依頼すると、ダンプしたメモリ範囲のどこにもないことがわかります。s_arrs_arrs_arr"4237""4237"s_arr

繰り返しますが、「0x...4f4 は rw 0x...4fc は ro であり、0x...504 は rw である」というあなたの主張は完全に間違っています。これらのアドレスはすべて読み取り専用です。それらのどれも読み書き可能ではありません。そこには「粒度」はまったくありません。

このような宣言を覚えておいてください

char s_arr[] = "4237";

本当に同等です

const char *unnamed = "4237";
char s_arr[5];
memcpy(s_arr, unnamed, 5);

メモリ ダンプでは、unnamed上記の例のアドレスを見ています。そのメモリ領域は読み取り専用です。あなたs_arrは、読み書き可能な完全に異なるメモリ領域に存在します。

于 2012-07-02T05:59:07.993 に答える
2

32 ビット プラットフォームが導入されてから、すべてが同じセグメントに配置されます (正確にはそうではありませんが、そうであると考える方が簡単です。説明に数ページを必要とする小さな警告があり、オペレーティング システムの設計に適用されます)。 .

32 ビットのアドレス空間は、いくつかのページに分割されています。Intel では、ページの粒度で RO ビットを割り当てることができます。デバッガーは、技術的にはセグメント内のオフセットである 32 ビット (64 ビット) アドレスのみを表示します。このオフセットを単にアドレスと呼んでも問題ありません。これで間違いはないでしょう。

それにもかかわらず、リンカはさまざまなメモリ領域をセグメントとして呼び出します。これらのセグメントは、Intel メモリ セグメントとは関係ありません。リンカー セグメント (コード、データ、スタックなど) は、diffrenet ページに読み込まれます。これらのページは、異なる属性 (RO/RW、実行許可など) を取得します。

于 2012-07-02T05:33:24.347 に答える
0

表示しているメモリのブロックは、文字列定数が格納されている領域です (4 つの値すべてが直接隣り合っていることがわかります)。この領域は読み取り専用としてマークされています。Windows では、メモリの各 4Kb ブロック (ページ) が独自の属性 (読み取り/書き込み/実行) を持つことができるため、隣接する 2 つの場所でも異なるアクセス フラグを持つことができます。

変数がある領域は別の場所にあります(あなたの場合はスタック)。&sイミディエイト ウィンドウ (またはウォッチ ウィンドウ)の値を確認することで確認できます。

于 2012-07-02T05:34:36.070 に答える