10

このコードをMSVSC ++ 2010で実行すると、次のようになります。

#include <iostream>

int main() {
    const int a = 10;
    const int *b = &a;
    int *c = (int *)b;
    *c = 10000;
    std::cout << c << " " << &a << std::endl;
    std::cout << *c << " " << a << " " << *(&a) << std::endl;
    return 0;
}

出力は次のとおりです。

0037F784 0037F784
10000 10 10

そのコードを書く動機は、Stroustrupによる「C ++プログラミング言語」からのこの文でした:「明示的な型変換によってconstへのポインターの制限を明示的に取り除くことが可能です」。

定数を変更しようとするのは概念的に間違っていることは知っていますが、この結果は非常に奇妙だと思います。誰かがその背後にある理由を説明できますか?

4

2 に答える 2

7

明らかなことから始めましょう:これのいくつかはプラットフォームとコンパイラに依存しています。

手始めに、明示的な型変換に関するこの記事を参照してください。特に、次のようになります。

型のオブジェクトconstへのポインタは、非型へのポインタにキャストできますconst結果のポインタは元のオブジェクトを参照します。型のオブジェクトconstまたは型のオブジェクト constへの参照は、非型への参照にキャストできますconst。結果の参照は、元のオブジェクトを参照します。そのようなポインタまたは参照を介してそのオブジェクトを変更しようとすると、アドレス指定の例外が発生するか、元のポインタまたは参照が非定数オブジェクトを参照していた場合と同じになります。アドレス指定の例外が発生するかどうかは、実装によって異なります。

それで、これは、なぜそれあなたが愚痴を言うことなく変数を修正することを可能にするかもしれないかを説明します。

キャスト演算子についてのこの記事で説明されているように、優先順位を指定してコンパイラが実行するので、キャスト演算子を直接使用して同じことを実現できることに注意してください。

ただし、ここでの本当の秘訣はメモリモデルにあります。const int aのような静的に割り当てられた変数は、実際にはメモリ内に「物理的な」場所を持たない可能性があり、コンパイル時にその場で置き換えられるだけです。(私はこれの実際の参照に指を入れようとしていますが、これまでのところ私がつかむことができる最も近くて最高のものはこれでした(非常に素晴らしい)だから答え決して使用されない静的変数に割り当てられたメモリですか? -誰かが実際の参照を見つけたら、お知らせください。)

したがって、ここでは、コンパイラは単にユーモアを交えて、ポインタ演算を可能な限り理解しようとしていますが、最終的には、2番目の呼び出しaの最後の2つの部分を実際の値に置き換えcoutます。

于 2012-11-08T23:48:49.383 に答える
0

その理由は、これが未定義の動作であるためです。

Stroustrupの引用は、オブジェクトが宣言されていないが、オブジェクトへのポインターconstしかない場合を指している可能性があります。const

つまり、これは明確に定義されています(問題に表示されるcスタイルのキャストを使用):

int a{10};
const int* pa = &a;

int* b = (int*)pa;
*b = 5;

そしてこれは未定義です:

const int a{10};
const int* pa = &a;

int* b = (int*)pa;
*b = 5;

宣言されたオブジェクトを変更しようとすると、constそれへの非定数ポインターを取得しますが、それはUBです。

于 2012-11-09T02:43:28.420 に答える