Jat*_*tin 1 c++ pointers integer const
我写了2个程序.请仔细阅读这两个程序并帮助我理解为什么变量'i'和'*ptr'给出不同的值.
//Program I:
//Assumption: Address of i = 100, address of ptr = 500
int i = 5;
int *ptr = (int *) &i;
*ptr = 99;
cout<<i; // 99
cout<<&i;// 100
cout<<ptr; // 100
cout<<*ptr; // 99
cout<<&ptr; // 500
//END_Program_I===============
//Program II:
//Assumption: Address of i = 100, address of ptr = 500
const int i = 5;
int *ptr = (int *) &i;
*ptr = 99;
cout<<i; // 5
cout<<&i;// 100
cout<<ptr; // 100
cout<<*ptr; // 99
cout<<&ptr; // 500
//END_PROGRAM_II===============
Run Code Online (Sandbox Code Playgroud)
困惑是:为什么变量我仍然是5,即使*ptr == 99?
在以下三行中,您正在修改常量:
const int i = 5;
int *ptr = (int *) &i;
*ptr = 99;
Run Code Online (Sandbox Code Playgroud)
这是未定义的行为.任何事情都可能发生.所以不要这样做.
至于在这种特殊情况下发生的事情:
因为i是const,编译器假定它不会改变.因此,它只是简单地将其5用于每个使用它的地方.这就是打印输出i显示原始值的原因5.
所有答案都可能会讨论"未定义的行为",因为您正在尝试修改常量的逻辑无意义.
虽然这在技术上是完美的,但是让我给你一些关于为什么会发生这种情况的提示(关于"如何",请参阅Mysticial回答).
之所以发生这种情况,是因为C++ 在设计上是一种" 不完美指定的语言 "."不完美"包含许多贯穿语言规范的"未定义行为".
事实上,语言设计师故意选择 - 在某些情况下 - 而不是说"如果你这样做,会给你那个",(可能是:你有这个代码,或者你有这个错误),他更喜欢说"我们不要定义会发生什么".
这使编译器制造商可以自由决定做什么.并且由于有许多编译器在许多平台上工作,可能是一个最佳解决方案,不一定是另一个的最佳解决方案(可能依赖于具有不同指令集的机器),因此您(作为程序员)留下在戏剧性的情况下,你永远不会知道会发生什么,即使你测试它,你也不能相信测试的结果,因为在另一种情况下(用不同的编译器编译相同的代码或只是不同的版本) ,或者对于不同的平台,它会有所不同.
这里的"坏"事情是编译器应该在遇到未定义的行为时发出警告(强制const应该被警告为潜在的错误,特别是如果编译器执行const内联otimizations,因为如果是const,它是无意义的如果你指定了正确的标志(可能是-W4或-wall或-pedantic或类似的,取决于你的编译器),可以允许更改).
特别是这条线
int *ptr = (int *) &i;
Run Code Online (Sandbox Code Playgroud)
应发出如下警告:
warning: removing cv-qualifier from &i.
所以,如果你把你的程序改正为
const int *ptr = (const int *) &i;
Run Code Online (Sandbox Code Playgroud)
为了满足回收,你会得到一个错误
*ptr = 99;
Run Code Online (Sandbox Code Playgroud)
如
error: *ptr is const
从而使问题显而易见.
故事的道德:
从法律角度来看,你编写了错误的代码,因为它是-by语言定义 - 依赖于未定义的行为.
从道德的角度来看:编译器保持不公平的行为:在接受后执行const-inlining(替换cout << i为cout << 5)是一种自我矛盾,至少应该警告不连贯的行为.如果它想做一件事就不能接受另一件事,反之亦然. (int*)&i
因此,检查是否有可以设置警告的标志,如果没有,请向编译器制造商报告其不公平性:它没有警告其自身的矛盾.