2

このコードは、MSVisualStudioでは奇妙な動作をします。

char *s = "hello";
s[0] = 'a';
printf(s); 

最適化がオンになっているリリースビルドでは、s [0] ='a'を無視し、「hello」を出力します。最適化なしまたはデバッグビルドでは、アクセス違反でクラッシュします。
この動作はC++標準に準拠していますか、それとも準拠していませんか?私の意見では、コンパイラは文字列リテラルへの定数参照のみを許可する必要があります。

const char *s = "hello";

編集:私はそれがこのように機能する理由を知っています、私はなぜ私が読み取り専用メモリに非定数参照をすることが許されているのか理解していません。

4

6 に答える 6

14

いいえ、コンパイラのバグではありません。あなたが書くとき:

char* s = "hello";

文字列定数"hello"は読み取り専用セクションに配置され、変更しようとすると例外が生成されます。(C++ 例外ではなく、OS 例外)。

書き込み可能にするには、配列を使用する必要があります。

char s[] = { 'h', 'e', 'l', 'l', 'o', 0 };

または、本当にポインターが必要な場合は、配列を指すようにします。

char _s[] = { 'h', 'e', 'l', 'l', 'o', 0 };
char* s = _s;

文字列リテラルでの const ポインターの初期化のみを許可するというあなたの指摘は理解できますが、それは多くの既存のコードを壊すと思います。

于 2009-02-23T16:20:46.397 に答える
7

そもそもこのコードが許可されている理由 (宣言が type であることを要求するのではなくchar const*) は、古い C コードとの下位互換性のためです。

ただし、厳密モードの最新のコンパイラのほとんどは、上記のコードに対して警告を発行します!

于 2009-02-23T16:28:56.393 に答える
3

C++ コンパイラは、標準に従って読み取り専用メモリ ページに文字列リテラルを割り当てることが許可されていると思います。

于 2009-02-23T16:19:24.000 に答える
2

*s は、変更が許可されていない文字列定数のメモリアドレスを指しているため、これは機能しません。

最適化してコンパイルすると、アクセス違反が発生しないことに、実際には少し驚いています。

于 2009-02-23T16:20:59.923 に答える
1
char *s = "foo";

トリッキーなポニーです。実際には読み取り専用の文字列であることはわかりません。これは、同僚に次のような別の文字列を書いてもらうことができるためです。

char *t = "foo";

さて、コンパイラは、最善を尽くしてもコピーを 1 つだけ保持し、1 つを変更することは、あなたとあなたの友人を満足させるためだけに多くの作業を意味します。だから、それをしようとはしません。これは、標準で見つける必要があるものです。あなたがしていることはUBを呼び出すと思います。

とはいえ、もしあなたが自分の思い通りになれば、標準化委員会の貧弱な連中が手に入れることができなかった多くのレガシー コードを壊すことになるでしょう。それで、そこにいます。

const私たちはのんきな使用に罪を犯していることを忘れないでください。Bjarne は多くの魂の探求を行い、それを入れるかどうかにかかわらず、他の多くの人もそうしました。実際、彼は読み取り専用と書き込み専用の変数を持つという優れたアイデアを持っていました...しかし、その話は別の日に取っておきます。

そして最後に、世話をしなければならない親友 C がいます。そう ...

于 2009-02-23T16:28:28.797 に答える
0

他の人が言ったように、文字列リテラルを変更することはできません。また、コードでコンパイラの警告が表示されないのも不思議です。コンパイラは、読み取り専用メモリに書き込もうとしていることを確実に把握できます。

于 2009-02-23T16:25:07.887 に答える