偶然在CSDN的论坛上看到这样的题目,代码如下:
const int a=3;
int *p=(int*)&a;
*p=100;
printf("*p =%d,a = %d\n",*p,a);
printf("p = %p,a = %p\n",p,&a);
程序中p和a的地址一样,可值不一样,容易让人产生错觉。有人说这样做改变了常量a的值,调试跟踪中发现a的值是100,可输出的却是3;还有人认为是常量折叠的缘故。其实这两种说法都是错误的,没抓住问题的本质。在这个程序中,通过int *p=(int*)&a;这个语句,常量a和指针p的地址是一样的,但是由于它们所属的内存区的不同,在栈区我们看到*p值是100,常量区的值是3.
在C++中,常量确实不分配内存,但是当对常量取地址时就已经分配了空间,常量是不可以改变的,但我们要记住的是:常量和常量的地址是两个概念,常量不可以改变,但是常量的地址可以改变,所以说,改变了常量a的值,说法是不正确的;至于在调试中,发现a的值是100(VC编译器的调试模式下的观察窗口下,用鼠标点到a的地址处),可输出的是3,那是因为,常量a和变量p是一个地址,但是却分属不同的内存区域,a是常量区,p是栈区,我们观察的地址在栈中,所以看到的值是100(其实是存储在指针p指向的地址中的值100),可输出a的值3,a的值并没变;这里和常量折叠的关系不大,至少不是它的实质,如果把const去掉值就一样了。
值得注意是:这样的代码容易让人产生错觉,如果再有内存分配的话,很容易出问题,并不提倡这样的代码。一直一来认为,C++很大,注重的是细节,这里再次验证了这一点。