#define是个真常量,在编译时,代码中的宏名称将被替换掉。const常量是一个假常量,使用const定义的变量最终还是个变量,只是在编译器内进行检查, 若发现被修改则报错。既然被const修饰的变量本质没有改变,那么就可以修改,这里不说它的实用性。(const的其他情况,比如修饰类中的数据成员,成员函数等,以后再讨论)
int main() { int i=1; const int b=2; const int *p1=&i;//不同通过指针p1修改i的值,但p1的值可以改变,即可以给p1重新赋值 int const *p2=&i;//与p1完全一样 int * const p3=&i;//p3不能指向const对象,不能给p3重新赋值,但可以通过p3修改i的值。 const int * const p4=&i;//既不能通过*p4修改i的值,也不能对p4重新赋值。 const int &p5=i;//引用必须初始化,不能重新赋值,同时此处不能通过p5修改i的值。 int *p=(int *)&b;//不能将一个const对象赋给一个非const指针, //但可以对const对象进行强制类型转换,去掉const修饰,从而修改const对象的数据 *p=20;//修改const int b的值 cout<<b<<endl; system("pause"); return 0; }
输出结果b的值依然是2,但并不说明b不能修改,只是编译器在编译期间发现b被const修饰,之后所有使用b的地方都被替换为其常量值。所以cout<<b<<endl在编译期间被优化为
cout<<5<<endl;
通过调试可以看到,通过指针p修改了const常量b的值。
int i=1; 00F813BE mov dword ptr [i],1 const int b=2; 00F813C5 mov dword ptr [b],2 const int *p1=&i;//不同通过指针p1修改i的值,但p1的值可以改变,即可以给p1重新赋值 00F813CC lea eax,[i] 00F813CF mov dword ptr [p1],eax int const *p2=&i;//与p1完全一样 00F813D2 lea eax,[i] 00F813D5 mov dword ptr [p2],eax int * const p3=&i;//p3不能指向const对象,不能给p3重新赋值,但可以通过p3修改i的值。 00F813D8 lea eax,[i] 00F813DB mov dword ptr [p3],eax const int * const p4=&i;//既不能通过*p4修改i的值,也不能对p4重新赋值。 00F813DE lea eax,[i] 00F813E1 mov dword ptr [p4],eax const int &p5=i;//引用必须初始化,不能重新赋值,同时此处不能通过p5修改i的值。 00F813E4 lea eax,[i] 00F813E7 mov dword ptr [p5],eax int *p=(int *)&b;//不能将一个const对象赋给一个非const指针, 00F813EA lea eax,[b] 00F813ED mov dword ptr [p],eax //但可以对const对象进行强制类型转换,去掉const修饰,从而修改const对象的数据 *p=20;//修改const int b的值 00F813F0 mov eax,dword ptr [p] //从指针p中取出b的地址放到eax中,然后将20存放到eax也就是b的地址中 00F813F3 mov dword ptr [eax],14h cout<<b<<endl; 00F813F9 mov esi,esp 00F813FB mov eax,dword ptr [__imp_std::endl (0F882A4h)] 00F81400 push eax 00F81401 mov edi,esp 00F81403 push 2 //可以看到这里push的是2,而不是b地址中的数据,这就是对常量优化的结果(常量传播)
#define、const这两种类型在连接生成可执行文件后将不复存在。