关于常量传播(如何修改const常量的值)

今天在回顾C++的const_cast的时候无意写了这样一段代码:

#include
using namespace std;
int main(){
	const  int i=100;
	int *p=const_cast(&i);
	(*p)++;
	cout<

运行结果如下:
0x22ff74 0x22ff74
101 100

结果分析如下:

1、首先给出const_cast的说明,《C++ primer》第五版中这样写道:“const_cast只能改变运算对象的底层const。如果对象本身不是一个常量,使用强制类型转换获得写权限是合法行为。然而如果对象本身是一个常量,再使用const_cast执行写操作就会产生未定义的行为。”

但是,以上代码中int型变量i本身是const的,利用const_cast消除了i的底层const,并让非const指针p指向i,通过p对i进行写操作。在code blocks和VS 2010下运行该程序,编译通过,并且int型常量i的值均被修改。不知《C++ primer》上所说的“未定义的行为”该如何理解。

2、字面值常量100存放在常量存储区中;int型常量i,因为是局部的,我认为应该是和普通的局部变量一样存储在栈中。

3、最后打印i的值仍是100。原因是常量传播,又称常量替换,在编译阶段,编译器直接将程序中的i替换为10,所以打印i的结果为10。但i在栈上的值确实是被修改掉了!


*************************** add in 2014-12-21***************************

今天看《C++反汇编与逆向分析技术》2.6.2 #definde和const的区别。书上给出了和上面代码类似的代码,还真是很巧,也记不清大半年前怎么会写出这段代码的。书中讲到#define定义的常量是真正的常量(保存在常量区),而const却是由编译器判断实现的常量,是一个假常量。const常量本质上还是一个变量,只不过C++中提出的const机制在编译层面上对const常量提供了写保护,是为了防止意外修改。

既然const常量是假常量,那就肯定是能修改的,修改方法见上面代码(获取指针,强制将指针的const修饰去掉,再通过指针修改之)。这种通过指针绕过const机制的代码在平时的编码中自然没什么意义,但在逆向工程中却是有意义的。


*************************** add in 2014-12-25***************************

不要混淆常量传播和常量折叠,两个都是编译器的优化手段(目的是在不影响程序正常逻辑的前提下,尽可能生成立即数寻址的目标代码,减少内存的访问次数)。VS下开启O2优化后,会进行常量传播和折叠。详见《C++反汇编与逆向分析》P49

你可能感兴趣的:(c++)