2.6.2 #define和const的区别

#define是一个真常量,而const却是由编译器判断实现的常量,是一个假常量。在实际中,使用const定义的变量,最终还是一个变量,只是在编译器内进行了检查,发现有修改则报错。

由于编译器在编译期间对const变量进行检查,因此被const修饰过的变量是可以修改的。利用指针获取到const修饰过的变量地址,强制将指针的const修饰去掉,就可以修改对应的数据内容,如代码清单2-12所示。

代码清单2-12 修改const常量


//C++源码对比,将变量nConst修饰为const

const int nConst=5;

;将地址ebp-4赋值给4字节数据5

004010B8 mov dword ptr[ebp-4],5

//C++源码对比,定义int类型的指针,保存nConst地址

int*pConst=(int*)&nConst;

;获取ebp-4地址并存入eax中

004010BF lea eax,[ebp-4]

;将eax中的数据赋值到地址ebp-8处

004010C2 mov dword ptr[ebp-8],eax

//C++源码对比,修改指针pConst并指向地址中的数据

*pConst=6;

;获取地址ebp-8中的数据并存入ecx

004010C5 mov ecx, dword ptr[ebp-8]

;将地址ebp-8中保存的数据修改为6

004010C8 mov dword ptr[ecx],6

//C++源码对比,将修饰为const的变量nConst赋值给nVar

int nVar=nConst;

;将5赋值到地址ebp-0Ch处

004010CE mov dword ptr[ebp-0Ch],5


在代码清单2-12中,由于const修饰的变量nConst被赋值一个数字常量5,编译器在编译过程中发现nConst的初值是可知的,并且被修饰为const。之后所有使用nConst的地方都以这个可预知值替换,故int nVar=nConst;对应的汇编代码没有将nConst赋值给nVar,而是用常量值5代替。如果nConst的值为一个未知值,那么编译器将不会做此优化。在示例中使用指针能否将nConst中的数据修改为6呢?我们先来看看图2-15。

图 2-15 const常量的修改结果

图2-15中演示了const修饰的变量被修改后的情况。被const修饰后,变量本质上并没有改变,还是可以修改的。#define与const两者之间还是不同的,如表2-4所示。

这两者在连接生成可执行文件后将不复存在,在二进制编码中也没有这两种类型存在。在实际分析中,读者需要根据自身的经验进行还原。