c++用关于const变量的疑问

首先看下面一段代码:

 #include <iostream>

using namespace std;

int
main()
{
    const int i = 10;

    int *pi = const_cast<int *>(&i);
    ++*pi;
    cout << "  i = " << i << ", @" << &i << endl;
    cout << "*pi = " << *pi << ", @" << pi << endl;

}

运行结果是:

i = 10, @0x28ff44

*pi = 11, @0x28ff44

我想问的是,变量 i 的值到底有没有被改变?问什么同一个地址输出的值不一样?

这里是编译器决定的,你用VS2008调试就会发现,i的值在调试窗口里都是变化了的。但是const表示的是一个常量,不可变的,如果用const-cast又可将它改变,就自相矛盾了。
于是编译器采取了一种方案,在汇编里可以看出端倪:

    cout << "  i = " << i << ", @" << &i << endl;
004142B8  mov         esi,esp 
004142BA  mov         eax,dword ptr [__imp_std::endl (41A348h)] 
004142BF  push        eax  
004142C0  mov         edi,esp 
004142C2  lea         ecx,[i] 
004142C5  push        ecx  
004142C6  push        offset string ", @" (417880h) 
004142CB  mov         ebx,esp 
004142CD  push        0Ah  
004142CF  push        offset string "  i = " (417878h) 
004142D4  mov         edx,dword ptr [__imp_std::cout (41A34Ch)] 
004142DA  push        edx  

10是直接使用的(见上面的push 0Ah),并不是按我们的惯性思维从地址里去取的。

const_cast并不允许修改原来的常量值,c++里const_cast转换一个常量值的结果是未定义,i的值并不会改变,而pi里的值是个随机的值

从 VS2008 编译器的内存来看,这个地址 0x28ff44 的值已经是 11 了。

应该是 VS2008 等 编译器做了处理,i 是不可变的,在输出 i 时并没有从内存中去读取数据。

变量i的值应该是不变的吧

如果在 i 的定义前增加 volatile ,则可以看到最后的输入结果: i =11;

{
volatile const int i = 10;

    int *pi = const_cast<int *>(&i);
    ++*pi;
    TRACE("i = %d;@i = 0x%x\r\n",i,&i);
    TRACE("pi = %d,@pi = 0x%x\r\n",*pi,pi);

    TRACE("\r\n");
}

输出为:
i = 11;@i = 0x12edb0

pi = 11,@pi = 0x12edb0
以上为 VS2005 编译、运行的结果。

你的i地址发生了强制转换了。。。

我将程序在vs2012和g++上都试了,它们结果一样的。很明显我们可以肯定,使用const_cast可以返回一个非常量指针指向常量。
并且可以改变常量的值,即原来存放该常量的地址的内容被改变。要确保不出错就应该使用对返回的指针的解引用,而不要再去使用原来存放常量的那个变量(常量)。

如果const int i = 10;定义成全局的,或前缀static。您再如此这般的试一试。嘿嘿!