3

memcpyでconst変数へのポインターを使用してconst変数を変更できるのはなぜですか?

このコード:

const int i=5;
int j = 0;
memcpy(&j, &i, sizeof(int));
printf("Source: i = %d, dest: j = %d\n", i,j);

j = 100;
memcpy(&i, &j, sizeof(int));
printf("Source: j = %d, dest: i = %d\n", j,i);
return 0;

警告だけでコンパイル:

警告:「memcpy」の引数1を渡すと、ポインタターゲットタイプから「const」修飾子が破棄されます[デフォルトで有効]

しかし、問題なく実行され、const変数の値が変更されました。

4

4 に答える 4

7

const修飾変数の値を変更しようとすると、Cで未定義の動作が発生します。何かが発生する可能性があるため、結果に依存しないでください。

C11(n1570)、§6.7.3型修飾子

非const修飾型の左辺値を使用して、const修飾型で定義されたオブジェクトを変更しようとした場合、動作は未定義です。

コンパイラに診断メッセージを生成させるものはありません。

実際、この修飾子はマシンコードに大きな影響を与えません。const修飾変数は通常、読み取り専用データセグメントには存在しません(他の変数とは異なる可能性がありますが、明らかに、実装には存在しません)。

コンパイラーは、特定の関数でポインターが何を指しているのかを簡単に判断できません。ポインタ分析を実行するいくつかの静的分析ツールで可能です。ただし、実装は難しく、標準化するのはばかげています。

于 2013-03-20T13:06:31.357 に答える
7

質問は理由を尋ねます。理由は次のとおりです。

これが許されるのは、メモリアドレスへのポインターを取得すると、言語はそれが何を指しているのかわからなくなるためです。変数、構造体の一部、ヒープ、スタックなど、何でもかまいません。したがって、書き込みを禁止することはできません。直接メモリ アクセスは常に安全ではなく、別の方法がある場合は避ける必要があります。

割り当て(またはインクリメントなど)で a の値を変更するのconstを止めます。constこの種の突然変異は、const に対して実行できないことを保証できる唯一の操作です。

これを調べる別の方法は、静的コンテキスト (つまり、コンパイル時) と実行時コンテキストの分割です。たとえば、変数への割り当てを行う可能性のあるコードをコンパイルすると、言語は「それは許可されていません。const です」と言うことができ、それはコンパイル エラーです。この後、コードは実行可能ファイルにコンパイルされ、それが であるという事実constは失われます。変数宣言 (および言語の残りの部分) は、コンパイラへの入力として記述されます。コンパイルされると、コードは関係ありません。consts が変更されていないことを示すために、コンパイラで論理的な証明を行うことができます。コンパイルされたプログラムが実行され、コンパイル時にルールを破らないプログラムを作成したことがわかります。

ポインターを導入すると、実行時に定義できる動作が得られます。あなたが書いたコードは今では無関係であり、あなたはやりたいことを[しようと]することができます。ポインターが型付けされているという事実 (ポインター演算を許可し、ポインターの末尾のメモリを特定の型として解釈する) は、言語が何らかの助けを提供することを意味しますが、何かを行うことを妨げることはできません。ポインタはどこでも指すことができるため、保証はできません。コンパイラーは、ポインターを使用するコードで実行時にルールを破ることを止めることはできません。

つまり、ポインターは動的な動作とデータ構造を取得する方法であり、最も単純なコードを除いてすべてに必要です。

(上記には多くの注意点があります。つまり、コードのヒューリスティック、より洗練された静的解析バスは、一般的なコンパイラに広く当てはまります。)

于 2013-03-20T13:07:44.443 に答える
1

その理由は、C 言語では、任意のポインター型を type との間で暗黙的にキャストできるためvoid*です。void ポインタはジェネリック プログラミングに使用されるため、そのように設計されています。

したがって、C コンパイラは、この場合、プログラムが未定義の動作を呼び出しても、コードのコンパイルを停止することはできません。ただし、優れたコンパイラは、暗黙的に const 修飾子をキャストしようとするとすぐに警告を発します。

C++ は C よりも "強力な型付け" を備えています。つまり、このコードをコンパイルするには、ポインター型を明示的にキャストする必要があります。これは、C++ が実際に修正した C 言語の欠陥の 1 つです。

于 2013-03-20T13:47:25.710 に答える
-1

「公式には」実際には未定義ですが、非常に定義されています- const 変数の値を変更します。そもそもなぜ const なのかという疑問が生じます。

于 2013-03-20T13:33:31.913 に答える