5

コンパイラがなぜ与えるのか混乱しています

const char s[]="hello";
s[2]='t';                 // Compile Time Error

char *t = "hello";
*(t+2)='u';              // Run time Error

どちらの場合も、コンパイラはコンパイル時エラーを出すはずです。誰かがこれがこのようになる特定の理由を教えてもらえますか?

4

4 に答える 4

6

最初のケースでは、に書き込みを行っているconstと、コンパイラはそれに気づき、それを拒否できます。

2番目のケースでtは、は非constへのポインタなcharので、逆参照してで書き込むことができます*(t+2)。ただし、tは読み取り専用セグメントへのポインターで初期化されるため、実行時にセグメンテーション違反が発生します。

すべてのデータを書き込み可能なセグメントに配置するようにリンカーを簡単に構成できます。これは醜く、非標準です。

PS一部の高度な静的アナライザー(おそらくFrama-C)は、プログラムを実行せずに両方のエラーをキャッチする場合があります。たとえば、 MELTを使用してGCCを拡張し、そのようなチェックを追加することも想像できます(ただし、これは簡単な作業ではなく、資金を調達するのは難しいかもしれません)。

于 2013-03-11T08:05:55.927 に答える
6

下位互換性。

constcharを変更することはできません。それだけは明らかです。

明らかではないのは、文字列リテラルのタイプが実際には定数文字へのポインターであり、文字へのポインターではないということです。したがって、2番目の宣言のタイプは間違っています。ただし、これは歴史的な理由からサポートされています。


上記は少しうそであることに注意してください。文字列リテラルは、ポインタではなく、実際にはchar[]型です。

特に、文字列リテラルのタイプは、C89およびC99ではachar[]ではなくconst char[][C11だと思いますが、確かではありません]。実際には間違っていませんが、データは読み取り専用セグメントに格納されているため、書き込みを試みるのは未定義の動作です。


また、その価値については-Wwrite-strings、gcc(g ++にはすでに含まれています)で使用して、このことを警告することができます。


ここここの詳細情報。

于 2013-03-11T08:06:00.520 に答える
3

その場合char *t = "hello";tはコード部分にあるメモリを指すポインタであるため、変更することはできません。読み取り専用であるため、実行時にセグメンテーション違反が発生します。

const char s[]="hello";実行する場合:sはスタック上にあるcharの配列ですが、それconstは変更できないため、コンパイルエラーが発生します(コンパイラーはそれがconstであることを認識しているため、変更を許可していません) )。

const文字列を変更したくない場合に使用すると、コンパイルエラーが発生するため、実行時エラーよりもはるかに優れています。

于 2013-03-11T08:09:01.993 に答える
2

次の一連のステートメントについて考えてみます。

char *t = "hello";
char s[5];
t = s;
*(t+2)='u';

この一連のステートメントでは、ステートメント*(t+2)='u';が無効ではないため、実行時エラーは発生しません。あなたの場合、const(読み取り専用)メモリの場所を変更しようとしていますが、コンパイラはアクセス違反が発生するかどうかを知る方法がありません。

于 2013-03-11T08:08:08.977 に答える