最近复习的过程中发现网上对于const的说法不一,让人摸不着头脑,为了搞清其原理,决定通过反汇编的方式来看一看其内部究竟发生了什么,下面是一篇简单的介绍反汇编指令的文章,用来理解本次所研究的东西已经足够
https://www.lagou.com/lgeduarticle/1754.html
下面将按照一个观点一个例子的方式来进行:(该测试基于VS2017环境)
1.将字面值赋给const变量时,会在编译期间将程序中用到该变量的地方替换成对应的数值(类似于宏替换),同时该变量在内存中分配空间,通过指针也可以对该变量的内容进行更改,但不会影响到程序中使用const变量的地方,因为程序真正执行的时候,const变量所在的地方已经替换成了字面值,例如
#include<iostream> int main() { const int x = 12; int *ppx = (int *)&x; *ppx = 13; int b = *ppx; int c = x; std::cout << "*ppx = " << *ppx << " x = " << x << std::endl; std::cout << "b = " << b << " c = " << c << std::endl; system("pause"); }
其反汇编的结果为:
从结果分析可知,
在1处,程序将字面值0Ch直接赋值给了x变量
在2处,程序通过指针访问x变量的地址,将0Dh赋值给了x所在的内存位置
其过程可由下图看出
执行前:
执行后:
在3处,程序通过访问x变量所在的内存地址将值取出并赋给变量b
在4处,本应将x变量的值赋给变量c,但在反汇编结果中可见,程序将字面值0Ch直接赋给了变量c,而没有通过地址取值
2.若通过一个变量赋值给一个const变量,那么上面的说法将不再成立,经过试验发现,此种情况下const限制只对变量名访问有效,对于指针修改的方式并不能起到限制写的作用,试验过程如下:
#include<iostream> //此代码相对于上一个例子只是将x变量赋值的方式改变,其余位置不变 int main() { int y = 12; const int x = y; int *ppx = (int *)&x; *ppx = 13; int b = *ppx; int c = x; std::cout << "*ppx = " << *ppx << " x = " << x << std::endl; std::cout << "b = " << b << " c = " << c << std::endl; system("pause"); }其反汇编的结果为:
此次反汇编结果仅1,2两处与先前不同,中间部分一致,不再赘述
从结果分析可知:
通过变量赋值方式初始化的const变量,其赋值时需要访问原变量的地址
通过此方式初始化的const变量,在使用时也会到内存中取它的值,而不会像上一个例子中一样做宏替换
3.代码中出现字符串的地方都会在内存常量区中保存,若同一个字符串在代码中多次出现,编译器会自动识别,不会重复产生同样的串
#include<iostream> #include<string> int main() { std::string *s = new std::string("aaa"); const char *cptr = "aaa"; char * cptr1 = (char *)"bbb"; char ch[] = "aaa"; system("pause"); }其反汇编的结果为:
观察1.2.4可看出,当程序中使用同一个字符串时,编译器并不会产生新的串,而是共用一块地址中的内容,当串不同时,才会在常量区中保存新的串
观察2.3并结合图二可看出,当使用指针指向常量区中的地址时,由于常量区的内容本身就是不可更改的,因此,用不用const都是一样的,即使强制类型转换为普通指针修改了其中的内容,也会在运行时产生异常
观察2.4可看出,使用指针指向常量时,指针变量内存入的是常量区中常量的地址值,而使用字符数组保存字符串时,编译器会将常量区中的常量复制一份赋给栈中的字符数组空间