谁可以帮我解释解释!!!

sixbusy 2007-04-04 07:37:16
#include <stdio.h>
#include <iostream.h>
void main()
{

const int i = 10;
int *p;
p = (int *)&i;
*p = 9;
cout<<i<<" ------ "<<*p<<endl;
cout<<&i<<" ------ "<<p<<endl;

}
结果: 10 9
谁可以告诉我为什么??
p存放在哪里??和i相同吗??为什么值不同??
谢谢!!
...全文
466 22 打赏 收藏 转发到动态 举报
写回复
用AI写文章
22 条回复
切换为时间正序
请发表友善的回复…
发表回复
kouzhongling 2007-04-05
  • 打赏
  • 举报
回复
就喜欢和别人论战了 呵呵
说是bug也许是有些夸张而已
不过这个问题看如何看待
对于const int i = 9;这样的句子 编译器 也许 就是用符号表中相应初值直接替换调
对于i的访问完全是段属性来控制,编译器不管它是不是能修改

问题是const 既然修饰了i 是不是应该保证它不被修改的问题

根本原因也不是 i 是 常量 或 变量
而是i 放到什么地方

当编译器要把const修饰的i放在像栈这样的可读写地方时,是不是要提供一个警告
txk1452 2007-04-05
  • 打赏
  • 举报
回复
========================================================================
有趣!
这应该是编译器的一个bug(说是bug是因为const不能确保栈中的常量不被修改)
========================================================================
哈哈,不太同意思此说法!~~~~
下面来给大家做个分析吧!~~~~
看这样一个程序:
#include<iostream>
using namespace std;
int g1=0, g2=0;

void main()
{
int l1 = 0 , l2 = 0;
static int s1 = 0, s2 = 0;

cout << &l1 <<endl;
cout << &l2 <<endl;
cout << &g1 <<endl;
cout << &g2 <<endl;
cout << &s1 <<endl;
cout << &s2 <<endl;

system("pause");
}
在我机器上输出结果为:
0012FF7C
0012FF78
0047875C
00478760
00478764
00478768
请按任意键继续. . .

从后四行可以看出,其实g1,g2,s1,s2是连续存储的(程序低端内存区域中),而l1,l2是和他们就相差很远了!~~~(在程序高端内存区域中),这也就是所说的静态区和动态区的问题了啊!~~~
对于全局变量和静态变量一律保存在静态区中,程序只要还运行着他们就会永远的存在,而局部变量使终保动态区中,在一函数返回时生命期就结束了(当然还有其它情况不多说了),

现在在来分析程序,

void main()
{

const int i = 10;
int *p;
p = (int *)&i;
*p = 9; //const int i确实被修改了,编译器没提供任何报错
cout<<i<<" ------ "<<*p<<endl;
cout<<&i<<" ------ "<<p<<endl;

}
此处的i应是在动态区了,它是堆栈(stack和heap).栈是一种线性结构,堆是一种链式结构。
每个线程都有私有的“栈”来保证本地变量的数据都是互不干扰的。
此处在i为const对象,i并不能被修改!~而p = (int *)&i;指像了i存储单元的地址,这可不是const对象,*p = 9;这也就不会有问题了!~~~~

再看,

==============================
#include<iostream>
using namespace std;
#define MAX 100
const int i = 10; //放入常量区(此处是静态区)
void main()
{

int *p;
p = (int *)&i;
*p = 9; //编译器报错!!!
//(此处不是编译器报错只是运行时内存不能被write)
cout<<i<<" ------ "<<*p<<endl;
cout<<&i<<" ------ "<<p<<endl;
system("pause");
}
这里的i是在静态区中,(注意:可不是动态区哦)!~~~至于这里的内存为什么是不能被write而上面的动态区却可以呢!~~~大家想想,如果还有其它函数也要用这个i会出现会什么情况呢!~~`
这就不用我多说了吧!~~~

讲到这也应该说结论了!~~~
对于const int i在动态区中被修改不会影响到其它的函数!~~~而静态区则不是了。其实是一种const保护机制,对于动态区中的const对象,他每次在使用时,其实并不去访内存取此数!~~~而是直接从符号表中取得定义是候的那个值(二楼的反汇编结果也是正确的)。
而对于静态区的const对象,是不能被修改的(影响到其它函数了),用户程序对此存储单元只有read权限,如果你要写这个单元,则一定发生中断!~~~除非你比校牛,进入系统ring0级并找此单元对它强写,但这样程序是否崩溃就不知道了!~~~~
在看下面,
void main()
{

static const int i = 10;
int *p;
p = (int *)&i;
*p = 9; //此处同样是不能被write(i存在了静态区中了)
cout<<i<<" ------ "<<*p<<endl;
cout<<&i<<" ------ "<<p<<endl;

}
这并不是编译器的bug,想想开发编译器的人比我们哪个都聪明,怎么能说这就是bug呢?
打了好多字,好累!~~嘿嘿!~~~
kouzhongling 2007-04-05
  • 打赏
  • 举报
回复
理论上栈上的 符号确实 系统和编译器没必要提供保护
const失去它声明的意义
不知道编译器的设计者如何考虑的

没见过const用在栈变量的相关资料...
有见过的通知我一下
kouzhongling 2007-04-05
  • 打赏
  • 举报
回复
有趣!
这应该是编译器的一个bug(说是bug是因为const不能确保栈中的常量不被修改)
void main()
{

const int i = 10;
int *p;
p = (int *)&i;
*p = 9; //const int i确实被修改了,编译器没提供任何报错
cout<<i<<" ------ "<<*p<<endl;
cout<<&i<<" ------ "<<p<<endl;

}


==============================
#include<iostream>
using namespace std;
#define MAX 100
const int i = 10; //放入常量区
void main()
{

int *p;
p = (int *)&i;
*p = 9; //编译器报错!!!
cout<<i<<" ------ "<<*p<<endl;
cout<<&i<<" ------ "<<p<<endl;
system("pause");
}

wangzhangyong411 2007-04-05
  • 打赏
  • 举报
回复
不是存储俩个内存区的问题,是你编译的时候 编译器帮你把代码优化了,直接用10来代替i了,因为编译器认为反正是const的,就别再去内存中读取,提高效率,所以造成这个结果,而用const修饰的那个变量的内存区还可以被指针改变的解释就是,const的意思是说这个变量不能被改变,而不是说这个内存块不可变.象int const *a; const int *a;也是有区别的,一个是说这个指针不可变,另一个是说这个指针指的那块地方不可变.具体如何大家自己琢磨吧
sixbusy 2007-04-05
  • 打赏
  • 举报
回复
那就是和c中的#define一样了!!
是在扫描是就把与i的值替换了吗??
如果是符号表,那么i就有两个存储空间了!这是为什么??
Ronal_Lee 2007-04-05
  • 打赏
  • 举报
回复
楼上高手,我提问一个弱智的问题
这个符号表是在内存的什么地方啊?^_^
sixbusy 2007-04-05
  • 打赏
  • 举报
回复
很感谢大家对我的帮助,谢谢了!我真的看到什么是高手了!谢谢!
txk1452 2007-04-05
  • 打赏
  • 举报
回复
不好意思没打完贴上去了!~~
再把cout<<&i这行注释了,把 10 改为 11,重新编译一下,现在不存在extern const和引用他的地址了吧!~然后去内存中看看这个程序相对位移0012FF7C处,是不是我们现在的11
用WinHex打开内存,(注意思程序不要关了),打开这个进程的Primary Memory然后,然后跳转到0012FF7C处,看看是不是现在的11。反正我这边是的,如果在程序const int i = 11;下面定义一个int j = 12; 那么j地址一定为0012FF78,这正是堆栈进栈方式,由此说明const int i = 10,还是分配了存储空间!~~~~
还有编译器完全没有提出警告,本就不应该提出,如果我上面的测试是正确的话,那么编译器要提出警告的话,好像花出的代价应该不小吧!~~~不多说!~~~
高手们帮测试一下好了!~~~~


txk1452 2007-04-05
  • 打赏
  • 举报
回复
同意Ge的说法,用C来编译,用printf输出,那么结果就是9, 9。

=================================================================================
在C++中,通常并不会为const变量(即常量)创建存储空间,只是保存在符号列表里面,只有
显示使用extern const int i或者使用他的地址时候才会为它分配存储空间。
=================================================================================
实这种说法,网上也有这种说法!~~~但是我不知道你自己有没有真真的验证过,
我们来这样看看吧!~~~
void main()
{
const int i = 10;
cout << &i;
system("pause");
}
请把输出的结果记录下来!~~~~我这里是0012FF7C,


GeminiXXXCC 2007-04-05
  • 打赏
  • 举报
回复
对不起,最后写错了,p = const_cast<int *>(&i);
GeminiXXXCC 2007-04-05
  • 打赏
  • 举报
回复
在C和C++中,const的作用是完全不一样的。
LZ的代码,如果用C来编译,用printf输出,那么结果就是9, 9。
因为在C中,const变量就是一个普通变量,只是限定了他不能改变而已。
而在C++中,const变量是真正的常量,即汇编中的立即数,因此C++中,对i的调用,直接用10来代替,如同C中的#define一样。

在C++中,通常并不会为const变量(即常量)创建存储空间,只是保存在符号列表里面,只有
显示使用extern const int i或者使用他的地址时候才会为它分配存储空间。
至于对C++中(int*)&i其实就是一个const_cast转换,当*p改变时候,改变的只是为i分配的存储空间内的值,但是对于i的调用,还是一个立即数10。

因此出现10,9这样的结果是C++本身语意决定的,隐式的const转换也很正常,编译器完全没有提出警告的必要,不过书写时候还是显式调用比较好,p = const_cast<int *>&i;
txk1452 2007-04-05
  • 打赏
  • 举报
回复
哈哈,那我们看看进程在内存中的大概简单组织结构吧:
| |
| 代码段 |
__________________________
| |
| 静态区 |
__________________________
| |
| 进程堆 |
__________________________
| |
| 进程资源(一些句柄玩意) |
__________________________
| |
| 环境代码段 |
__________________________
| |
| 线程(1--n ) |
__________________________
在一般情况下,内存分配是从进程堆中分配的。包括定义局部变量,malloc,new !但是HeapCreate后HeapAlloc除外了!~~`关键是这个进程堆对大家来说是共用的啊!~~所说的const对象不能被修改,那也是相对的了!(总能想出一些修改的办法的,我不知道楼主是不是这个意图。想把const对象修改了)~~~其实这算是一种冲突吧!~~~因为人们要求const对象是不期望能被修改的!~~~~
1.其实从符号表中取原始的值是一种机制而言,我在在这也不要讨论那么深入!~~~
2.其实也可以不用符号表,也可以在进程堆中分出一个对用户程序只能读的段供const对象使用,(个人假想而言)
但是做编译器的人选择了在动态区定义const选择第一种方案,这也许可能和编译代码优化有关(我敢保证说在用到i时绝对不会去i内存单元拿值)、至于静态区的有可能是由操作系统段控制吧!~

至于"当编译器要把const修饰的i放在像栈这样的可读写地方时,是不是要提供一个警告",这个要问开发编译器的人了!~~~他们完全可以给大家一个警告;但是既然不会影响到程序运行的正确性的话,我看给不给警告也就无所谓了!~~~这样有可能增加应用程序员的负担!~~(完全个人想想而言)
对这个我想我们没必要去研究这么深入,毕竟我们都不是开发编译器的!~~~
如果有了这个水平,也就不用问这么多为什么了!~~~

Eric_wang1 2007-04-04
  • 打赏
  • 举报
回复
的确如此,真是学到了不少东西
txk1452 2007-04-04
  • 打赏
  • 举报
回复
&i和p都是指像了同一个存储空间,其实*p=9,此时i,*p都是9了,但是你的输出的时候i变成10,那是cout取的并不是存储空间的内容了,而是符号表中的内容,
#include <stdio.h>
#include <iostream.h>
void main()
{

const int i = 10;
int *p;
p = (int *)&i;
*p = 9;
cout<<i<<" ------ "<<*p<<endl;
cout<<&i<<" ------ "<<p<<endl;

int k = i; //此时k也是10符号表中的,而i存储单元中的值却是9,你可以设个断点调一下,就知道了

}
sixbusy 2007-04-04
  • 打赏
  • 举报
回复
你好!
谁可以指出各个变量的存储空间!
在这个过程中只有i有存储空间!!
那9存在哪里了??谁存放的它的地址!!
txk1452 2007-04-04
  • 打赏
  • 举报
回复
#include <stdio.h>
#include <iostream.h>
void main()
{

const int i = 10;
int *p;
p = (int *)&i;
*p = 9;
cout<<i<<" ------ "<<*p<<endl;
cout<<&i<<" ------ "<<p<<endl;

}
p和i存放在同一个存储单元中;
C++在定义一个const对象时将它们保存在符号表中,在整个编译期间都使用此符号表中的常量!~~
你程序中const int i = 10;定义和一个整型常量,在一般情况下是不能对i进行修改的,p = (int *)&i;使得p和i指向同一单元,其实执行完*p = 9;后,此单元内容也被改为9,但是输出的i值确是保存在符号表中的10,这就是保护const对象不能被修改!
你可以在main最后设置一个断点,然后调试,在watch中输入i,此时的i也是9,但是输出的是10是因为使用的是符号表中的值.
redfox1985 2007-04-04
  • 打赏
  • 举报
回复
是不是所有常量都是采用取代而不是存储呢?
常量的标识符只是什么呢?
为什么能去打地址呢?
地址里边存的是什么呢?
jixingzhong 2007-04-04
  • 打赏
  • 举报
回复
这样的修改,
可能程序会提示出错 ~
既然声明了是const,
那就不要有任何的改写操作。
jixingzhong 2007-04-04
  • 打赏
  • 举报
回复
常量折叠 ~~

cout<<i<<" ------ "<<*p<<endl;
这里的 i 直接被常量折叠为 10了,
编译优化后的语句是:
cout<<10<<" ------ "<<*p<<endl;
*p = 9; 这里被修改,
所以输出的就是 10 9
加载更多回复(2)

64,647

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧