修改const变量

转载 2016年05月31日 07:10:17

一、结论

声明:不同于C语言的const变量修改问题(可以通过指针间接修改const变量的值),这里只讨论C++ 里的const。

C++ const 修饰符,表示常量,即如果以后保证不会修改则声明为const,否则若要修改,那一开始为什么还要声明为const呢?

根据C++标准,对于修改const变量,属于:未定义行为(指行为不可预测的计算机代码),这样一来此行为取决于各种编译器的具体实现(即不同编译器可能表现不同)。

故结论就是:不建议这么做!

但是,是的,但是,网上论坛、博客里均有有关如何修改const变量的方法,其不是依赖于某种具体的编译器,就是讲的欠考虑。

方法是在定义变量的时候加上volatile关键字(没有其他方法了吗(比如,const_cast ...)? 是的,目前为止,我只知道这种方法是可能的):

  1. const volatile int i = 10;  

:关于volatile这里不细讲,详见:volatile 关键字。考虑到volatile的重要性,后面自己也会写一篇关于volatile详解的文章。

二、分析

为了说明问题,下面在三种编译器环境下做几个小实验

1. g++ 

  1. #include <stdio.h>  
  2. int main()  
  3. {  
  4.     const volatile int i = 10;  
  5.     int* pi = (int*)(&i);  
  6.     *pi = 100;  
  7.     printf("*pi: %d\n",*pi);  
  8.     printf("i: %d\n",i);  
  9.     printf("pi: %p\n",pi);  
  10.     printf("&i: %p\n", &i);  
  11.     return 0;  
  12. }  

输出结果:



gdb查看其汇编代码命令:进入gdb,然后输入:disass main):


可以看出:输入*pi 和 i 时均是从堆栈(即内存)中取数的。

反例:把 volatile关键字去掉:

  1. #include <stdio.h>  
  2. int main()  
  3. {  
  4.     const int i = 10;  
  5.     int* pi = (int*)(&i);  
  6.     *pi = 100;  
  7.     printf("*pi: %d\n",*pi);  
  8.     printf("i: %d\n",i);  
  9.     printf("pi: %p\n",pi);  
  10.     printf("&i: %p\n", &i);  
  11.     return 0;  
  12. }  

输出结果:


由此可见:在没有volatile关键字修饰时,const 变量 i 的值时没有改变的。

运用gdb查看其汇编代码:


注意此时(没有加volatile修饰符),输出 变量 i 的值时直接将 0xa(10)值(从符号表中取出的)输出,即此处编译器进行了优化,没有从内存中读。

注意到:指针 pi 和 &i(i 的地址)值却是一样的。So ,Why?

这就是C++中的常量折叠:指const变量(即常量)值放在编译器的符号表中,计算时编译器直接从表中取值,省去了访问内存的时间,从而达到了优化。

而在此基础上加上volatile修改符,即告诉编译器该变量属于易变的,不要对此句进行优化,每次计算时要去内存中取数。

这里也有个小细节:每种编译器对volatile修饰符的修饰作用效果不一致,有的就直接“不理会”,如VC++6.0编译器(下面会讲到)。

2. dev c++

运行结果与1(g++)一致。

3. VC++ 6.0

(1)添加volatile修饰符时,输出结果(程序代码同上):


 i 的值还是10,没有改变!这是为什么呢?不急,先看下其汇编代码:

注意:g++ 汇编代码的mov指令 与 VC++ 6.0的mov指令不同(传送方向相反)。


真相大白:虽然定义const变量的同时加上了volatile修饰符,但VC++ 6.0编译器还是进行了优化措施,输出 i 时 从编译器的符号表中取值,直接输出。

(2)无 volatile 修饰符时。输出结果:


i 的值没有改变,预期中。其汇编代码为:


结果与添加volatile时相同。

即在VC++6.0编译环境下,在const变量定义时添加volatile修饰符,与不添加效果是一样的。编译器都采取了优化(甚至把编译器优化选项关闭还是如此,有点恐怖...)。

4. VS 2010

再看下Microsoft编译器家族的高级版本:

(1)添加 volatile 修饰符时,输出结果:


 i 的值被成功修改了!

(2)无 volatile 修饰符时,输出结果:


i 的值没有被修改。

:不建议修改const变量的值,即使修改也要熟悉当前使用的编译器对于该 未定义行为 是如何解释的

参考文章:

1. change the value of const variable in C++ 

2. C/C++ changin the value of a const

3. 百度百科:C++ 常量折叠

4. volatile 关键字

const变量通过指针修改 详解

本来以为const变量是无法修改的,今天发现“错了”(其实没错,通过const变量本事是无法修改其值的,但是在“某些情况下”可以通过指向它的指针来间接修改) 一、const变量可以通过指针修改的情况 ...
  • hyqsong
  • hyqsong
  • 2016年03月12日 20:42
  • 1452

const变量真的不能修改吗?

昨天在写程序时,突然想到了一个问题:const变量真的不可改变吗?如果能改,应该怎么改?于是乎,就决定动手操作一番,结果程序的结果有点出乎意料。但是最终还是得出了结论。如有不妥,欢迎各位拍砖! 下面...
  • jhg1204
  • jhg1204
  • 2013年05月29日 15:49
  • 2333

C++中如何修改const变量

一、结论 声明:不同于C语言的const变量修改问题(可以通过指针间接修改const变量的值),这里只讨论C++ 里的const。 C++ const 修饰符,表示常量,即如果以后保证不会修改则声明为...
  • heyabo
  • heyabo
  • 2013年04月01日 12:30
  • 10981

c++中const变量真的不可以修改吗?

编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。 在学c++的时候,看到的大部分的书...
  • u011391093
  • u011391093
  • 2015年04月25日 12:33
  • 733

【C++】修改const变量的值

如下代码片段中声明const变量ci并初始化为1,原则上其值是无法被修改的。但是如下的代码对const变量的内容进行了修改int main(){ const int ci = 1; i...
  • Sugar_Z_
  • Sugar_Z_
  • 2015年08月29日 10:56
  • 891

C语言const:禁止修改变量的值

有时候我们希望定义这样一种变量,它的值不能被改变,在整个作用域中都保持固定。例如,用一个变量来表示班级的最大人数,或者表示缓冲区的大小。为了满足这一要求,可以使用const关键字对变量加以限定: c...
  • superywf
  • superywf
  • 2017年05月30日 22:25
  • 407

const和volatile变量是否可以同时修饰一个变量

问题:const和volatile是否可以同时修饰一个变量?有什么含义? 答案:如果一个变量不会被本程序改变,通常可能给它加上const,但如果该变量可能被其他程序改变而本程序又在检测这个变量的值,就...
  • u012523688
  • u012523688
  • 2014年04月02日 13:22
  • 1435

OC基本功(四)使用const修饰变量

用const修饰的变量表示变量值只读。 static有两个作用:指定变量的作用域和存储的方式。 两者结合可以设置作用域确定并且只读的变量,例如文件中的全局常量。...
  • u010962810
  • u010962810
  • 2014年02月02日 21:20
  • 3887

可以被const函数修改的非const变量----mutabel

原问是mutable variables and const functions mutable variables can be altered by const functions. But w...
  • haimian520
  • haimian520
  • 2016年11月30日 01:00
  • 335

C语言(关键字)

枚举类型 枚举是一种特殊的构造类型,它本身和int 是等价的,但它的值是有限个int 常量的合集,这些常量称为枚举符。 enum test{MON, TUE, WED, THU, FRI, SAT, ...
  • mrhjlong
  • mrhjlong
  • 2016年09月19日 11:15
  • 93
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:修改const变量
举报原因:
原因补充:

(最多只允许输入30个字)