7

この記事から。

register変数をandとして宣言するもう 1 つの用途は、変数constのアドレスを取得してからポインターをキャストすることによっても、その変数のローカル以外の変更を禁止することです。自分では絶対にそんなことはしないと思っていても、(const 属性を持っていても)ポインターを別の関数に渡してしまえば、これが悪意のあるものであり、自分の足元で変数を変更してしまう可能性があることを確信することはできません。

constポインターによって変数の値を変更する方法がわかりません。未定義の動作ではありませんか?

const int a = 81;
int *p = (int *)&a;
*p = 42; /* not allowed */
4

6 に答える 6

11

著者の要点は、ストレージ クラスで変数を宣言すると、registerそのアドレスを取得できなくなるため、キャスト アウェイによって値が変更される可能性のある関数に渡すことができないということですconst

void bad_func(const int *p) {
    int *q = (int *) p;            // casting away const
    *q = 42;                       // potential undefined behaviour
}

void my_func() {
    int i = 4;
    const int j = 5;
    register const int k = 6;
    bad_func(&i);                  // ugly but allowed
    bad_func(&j);                  // oops - undefined behaviour invoked
    bad_func(&k);                  // constraint violation; diagnostic required
}

潜在的な UB を制約違反に変更すると、診断が必要になり、コンパイル時にエラーが (必要に応じて) 診断されます。

5.1.1.3 診断

1 - 動作が未定義または実装定義として明示的に指定されていても、前処理の翻訳単位または翻訳単位に構文規則または制約の違反が含まれている場合、準拠する実装は少なくとも 1 つの診断メッセージを生成するものとします [...]。

6.5.3.2 アドレスおよび間接演算子

制約

1 - 単項演算子のオペランドは、 [...]ストレージ クラス指定子&で [...] が宣言されていないオブジェクトを指定する左辺値でなければなりません。register

配列オブジェクトでの配列からポインターへの減衰registerは未定義の動作であり、診断する必要がないことに注意してください (6.3.2.1:3)。

register左辺値のアドレスを取得することは C++ で許可されいることにも注意してくださいregister

于 2012-09-03T10:00:23.403 に答える
4

const変数の値を変更できますか?

はい、constさまざまな方法で変数を変更できます: ポインター ハッカー、キャストなど...
次の Q を読んでください!!

const変数の値を変更する有効なコードですか?

いいえ!それがあなたに与えるのはUndefined Behaviorです。

技術的には、コード例にはUndefined Behaviorがあります。
を変更すると、プログラムは c 標準に準拠していないconstため、何らかの結果が生じる可能性があります。

未定義の動作は、コンパイラが違反を診断として報告する必要があるという意味ではないことに注意してください。この場合、コードはポインター ハッカーを使用して a を変更するためconst、コンパイラーはその診断を提供する必要はありません。

C99 標準 3.4.3は次のように述べています。

未定義の動作:この国際規格が要件を課していない、移植不能またはエラーのあるプログラム構造またはエラーのあるデータの使用時の動作。

注記 未定義の可能性のある動作は、状況を完全に無視して予測不能な結果を​​もたらすことから、変換中またはプログラム実行中に環境に特有の文書化された方法で動作すること (診断メッセージの発行の有無にかかわらず)、変換または実行の終了 (診断メッセージの発行の有無にかかわらず) にまで及びます。診断メッセージの発行)。

于 2012-09-03T09:40:01.230 に答える
2

コードはコンパイルされますが、未定義の動作があります。

著者のポイントは、コードがコンパイルされないようにconst andを使用することです。 register

const int a = 81; 
int *p = (int *)&a; /* no compile error */
*p = 42; /* UB */ 

register const int b = 81; 
int *q = (int *)&b; /* does not compile */
于 2012-09-03T10:00:08.227 に答える
1

著者もこのケースについて話していると思いますが、これは次の誤解ですconst

 int a = 1;
 int* const a_ptr = (int* const)&a; //cast not relevant
 int function(int* const p){
     int* malicious = (int*)p;
     *malicious = 2;
 }

変数自体は定数ではありませんが、ポインタは定数です。悪意のあるコードは、通常のポインターに変換し、以下の変数を合法的に変更できます。

于 2012-09-03T09:56:56.163 に答える
1

コード フラグメントは実際に未定義の動作を呼び出します。

著者のポイントが何であるかはよくわかりません.「外部コード」が変数の値を変更しないようにするconstために...代わりにUBが呼び出されるようにしますか? それはどのように好ましいですか?率直に言って、それは意味がありません。

于 2012-09-03T09:44:17.953 に答える