目录
一、修改const修饰的局部变量
可以通过指针和强转来修改const修饰的局部变量。
#include <iostream> using namespace std; int main(void) { const int a = 1; int* pa = (int*)&a; *pa = 2; cout << a << endl; return 0; }
以上面的案例来讲const修饰的局部变量a会在编译时进行类似宏替换的预处理(编译器把代码中的局部变量a全都替换为常量1)。但局部变量a仍然存在栈上,a也仍然是一个变量,我们通过强制类型转换把a空间的访问权限扩大后让指针变量pa指向这个空间,此时我们就能通过pa来修改a指向的空间了。
但是上面代码的结果仍然是1,原因开头就说了:const修饰的局部变量a会在编译时进行类似宏替换的预处理,在运行前代码中的a就被宏替换为了1,所以即使a中的内容已经被修改,答应结果还是为1 。
通过反汇编可观测到这一现象:
二、无法修改const修饰的全局变量
const修饰的全局变量则更为特殊:它在全局(静态)区中的常量区中。这是一块不允许修改的空间,我们通过指针和强转,让指针变量p指向了这块空间,我们能访问到它,但是不能修改它。
const 修饰的全局变量是常量,放在常量区中,这是一块不能被修改的区域。而非const修饰的全局变量在全局区中,该区域允许被修改。
三、volatile关键字
volatile 是 C 和 C++ 中的一个关键字,它告诉编译器不要对该变量的访问进行优化,并且每次对该变量的读写都应该直接从其内存地址中进行。
举个例子:volatile可以阻止编译器在编译时对const修饰的局部变量进行类似宏替换的预处理。所以下面的代码结果和一中代码的结果不一样:
int main() { volatile const int a = 1; int* pa = (int*)&a; *pa = 2; cout << a << endl; return 0; }
通过反汇编也能观察到,a未进行类似宏替换的预处理:
面试题】
以下代码的运行结果是?
#include <iostream> using namespace std; int main(void) { const int a = 100; int* p = (int*)(&a); *p = 200; cout << "a = " << a << ", *p = " << *p << endl; cout << "&a:" << (int*)& a << endl; cout << "p:" << p << endl; return 0; }
- A. 编译或者运行阶段报错
- B. a = 100, *p = 100
- C. a = 200, *p = 200
- D. a = 100, *p = 200
- E. a = 200, *p = 100
答案是D,因为代码中的变量a在编译阶段进行类似宏替换的预处理,被替换为1 。而p通过指针+强转强制访问并修改了a所在的空间的内容。
------------------------END-------------------------
才疏学浅,谬误难免,欢迎各位批评指正。