请问个const类型强制转换的问题?

lazydot 2006-06-18 11:25:16
const long p=5;
cout<<"const long p is :"<<p<<","<<&p<<endl;
long* pa=(long*)&p;
*pa=10;
cout<<"const long p is :"<<p<<","<<pa<<endl;

------
打印出来的&p和pa的值,为什么*pa=10不能改变p的值呢?
与编译器有关吗?我用的dev-c++的
...全文
383 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
OOPhaisky 2006-06-24
  • 打赏
  • 举报
回复
点击右上角或者右下角的“管理”,就可以结贴了
lazydot 2006-06-24
  • 打赏
  • 举报
回复
怎么结帖阿?
lazydot 2006-06-24
  • 打赏
  • 举报
回复
结了
magicalking 2006-06-24
  • 打赏
  • 举报
回复
恩,我也试了下
int testt(){
return 1;
}


main(){
const long p=testt();
cout<<"const long p is :"<<p<<","<<&p<<endl;
long* pa=(long*)&p;
*pa=10;
cout<<"const long p is :"<<p<<","<<pa<<endl;
cin.get();
}
这样就可以看到改变了
lazydot 2006-06-24
  • 打赏
  • 举报
回复
感谢各位。
(long*)&p和pa指向同一个地址,而这个地址的值被改变了,
而编译器发现p被声明为const,所以常量叠加,阻止违规行为发生,好编译器!
beepbug 2006-06-24
  • 打赏
  • 举报
回复
你自己“规定”了p是个符号常量,又要在后面去改变它。
如果编译器没管住你的违法行为,那它是一个不称职的编译器。
如果管住了,你就不该质疑它了。表扬才对。
--------------------------------------------
我的BLOG:http://blog.csdn.net/beepbug/
OOPhaisky 2006-06-23
  • 打赏
  • 举报
回复
对于出现p的地方,编译器采用了常量折叠,
对于(long*)&p操作,编译器产生一个新的内存分配,并把常量的值赋给它。
--------------------------------------------------------------------
这个我不敢下结论,但是有一点是肯定的:对于long* pa=((long*)&p这样的操作,编译器肯定要保证p在内存中有一个固定的存储空间,否则指针pa就没有地方可指了。至于是不是“编译器看到((long*)&p之后才给p分配内存”我不敢肯定,也许不同的编译器有不同的实现方法吧。

最后再给楼主补充一点,并不是所有标有const的变量都能“常量折叠”,如:
int test();
const int a = test();
此处的a是无法常量折叠的,因为在编译时刻编译器无法确定a的值,直到程序运行时调用test后才能知道a的值。
303afei 2006-06-19
  • 打赏
  • 举报
回复
我感觉是常量折叠
lazydot 2006-06-19
  • 打赏
  • 举报
回复
long* pa=(long*)&p;
*pa=10;
难道是其实p指向的内存地址的 数据 已经被更改了,
只不过编译器把出现p的地方都用值5给替代了,所以打印错误?
fireseed 2006-06-18
  • 打赏
  • 举报
回复
triace_zhang所说的“复本”概念是不严谨的,应该说从来没有什么复本存在。

OOPhaisky讲的对
lazydot 2006-06-18
  • 打赏
  • 举报
回复
感谢3位!

所以迫使编译器给j分配存储空间。即分配了存储空间产生一个副本,把p值保存在
副本里。*pa = 10改动的只是内存副本中的内容,p的实际取值还是从常量表里读取

-----
原来是产生了副本。
long* pa=(long*)&p;只是获得了副本的地址,改变的也是副本的值。
怪不得
cout<<"const long *pa is :"<<*pa<<","<<pa<<endl;

可以打印出正确的赋值后的10.
OOPhaisky 2006-06-18
  • 打赏
  • 举报
回复
编译器在编译程序时分为几次扫描,很能在第一次扫描过程中将所有用到常量的地方用常量的具体值替换,这是所谓的“常量折叠”,所以你的程序很可能在第一次扫描后变成:
const long p=5;
cout<<"const long p is :"<<5<<","<<&p<<endl; //注意这里的“5”
long* pa=(long*)&p;
*pa=10;
cout<<"const long p is :"<<5<<","<<pa<<endl; //注意这里的“5”

所以,即使你用“*pa=10;”改变了p的实际值,但是输出结果是不会变的。
triace_zhang 2006-06-18
  • 打赏
  • 举报
回复
具体可以参考《C++编程思想》7.12 const 的安全性
triace_zhang 2006-06-18
  • 打赏
  • 举报
回复
这个问题和函数形参实参有点相似。
const引入最早是用来代替#define的。
比如: const int p = 10基本等价于 #define p 10;
p的值是存在编译器的常量表里面。p本身并不像普通变量一样在栈中建立一块内存段。
但是如果语句中有 long* pa=(long*)&p; cout << &p等,由于这些行需要p的
地址,所以迫使编译器给j分配存储空间。即分配了存储空间产生一个副本,把p值保存在
副本里。*pa = 10改动的只是内存副本中的内容,p的实际取值还是从常量表里读取。

void fun( int i ) //i是实参的一个内存副本
{
i++; //改变内存副本不能改变实参。
}

......
int j = 10;
fun(j); //j不变。
fireseed 2006-06-18
  • 打赏
  • 举报
回复
《C++Primer中文版 3RD》 P84.

……

一旦一个常量被定义了,我们就不能改变与const对象相关联的值。另一方面,我们能把它的地址赋值给一个指针吗?例如,下面代码是否可行?
const double minWage = 9.60;

// ok?错误了吗?
double *ptr = &minWage;
这是否可行呢?minWage是一个常量对象,因此它不能被改写为一个新的值。但是ptr是一个普通指针,没什么能阻止我们写出这样的代码:
*ptr += 1.40; //修改了minWage!
一般编译器不能跟踪指针在程序中任意一点指向的对象。[这种内部工作需要进宪数据流分析(data flow analysis),通常由单独的优化器(optimizer)组件来完成。]允许非const对象的指针指向一个常量对象,把“试图通过该指针间接地改变对象值”的地作标记为非法的,这对编译器来说是不可行的。因而任何“试图将一个非const对象的指针指向一个指向常量对象”的动作都将引起编译错误。

……


下面是我的话,不要搞混

const_cast可以用来去掉表达式的const性和volatile性,但它们仅是在转换“表达式”,它们并不能转换数字常量,看现下面的语句:
int x = const_cast<int>(5);
如果这句是可以通过编译的话,那程序中将无“常量”这个概念而言了。楼主明白了吗?
fireseed 2006-06-18
  • 打赏
  • 举报
回复
const 当然不能被改变,p在做为l-value时,指向一个地址,这个地址里面的初值是5,而且可以被改变,但当p做为r-value时,它就表示数字5,数字常量,永远不可能被改变,当
int x = p; 这句被编译后,应该是这个样子:
mov dword ptr[x] 5
triace_zhang 2006-06-18
  • 打赏
  • 举报
回复
自己用vc的内存查看器看看不就清楚有没有了。
lazydot 2006-06-18
  • 打赏
  • 举报
回复
感谢 OOPhaisky(渴望成功) 的补充
const long p=5;
cout<<"const long p is :"<<p<<","<<&p<<endl;
long* pa=(long*)&p;
*pa=10;
cout<<"const long p is :"<<p<<","<<pa<<endl;

cout<<"const long *pa is : "<<*pa<<","<<pa<<endl;

---------------------
对于出现p的地方,编译器采用了常量折叠,
对于(long*)&p操作,编译器产生一个新的内存分配,并把常量的值赋给它。

是这样吗?
哪位给个总结,3X

64,647

社区成员

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

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