守望者--AIR技术交流

标题: C++中对于const的理解 [打印本页]

作者: 破晓    时间: 2015-1-12 21:12
标题: C++中对于const的理解
C++Primer中并没有对const过多的解析,只说明为是一个使变量不可修改的限定符.但是仅仅知道这点对于我来说是远远不够的,const是怎么做到的限制修改?谁在帮const做这个限制?编辑器是怎么实现不可修改的?在认识const之前 我知道C++中唯一不可修改的就是常量,例如:


  1. int i = 1000;
复制代码

这个1000就是常量,除了修改生成的文件之外 任何方式都无法修改这个1000 .(修改生成的文件是怎么修改?例如生成了exe可执行文件,直接定位到代码区 找到这个变量定义的地方 把 1000的字节码E8 03 00 00改了..).

下面我们尝试下修改const声明的常量:

  1. void main()
  2. {
  3.     const int q = 1000;
  4.      printf("q1 = %d\r\n",q);
  5.      int *pQ = (int*)&q;
  6.      *pQ = 50;
  7.      printf("q2 = %d\r\n",q);
  8.      printf("pQ = %d\r\n",*pQ);
  9.      printf("q address:%d\r\n",&q);
  10.      printf("pQ address:%d\r\n",pQ);
  11.     getchar();
  12. }
复制代码

这段代码编译运行后输出:

  1. q1 = 1000
  2. q2 = 1000
  3. pQ = 50
  4. q address:1702152
  5. pQ address:1702152
复制代码

显然 const 常量 q 前后输出的都是1000.而q的指针修改后输出的是50.q的地址和pQ所指向的地址一样,输出的内容却不一样.这就让人奇怪了.按道理说 同一块内存(1702152) 改变了值之后所输出的内容应该也都是一样的(50)才对. 我们反编译看看编译器都做了什么:

  1.     const int q = 1000;
  2. 002C35EE  mov         dword ptr [q],3E8h  
  3.      printf("q1 = %d\r\n",q);
  4. 002C35F5  mov         esi,esp  
  5. 002C35F7  push        3E8h  
  6. 002C35FC  push        2CCC90h  
  7. 002C3601  call        dword ptr ds:[2D045Ch]  
  8. 002C3607  add         esp,8  
  9. 002C360A  cmp         esi,esp  
  10. 002C360C  call        __RTC_CheckEsp (02C1325h)  
  11.      int *pQ = (int*)&q;
  12. 002C3611  lea         eax,[q]  
  13. 002C3614  mov         dword ptr [pQ],eax  
  14.      *pQ = 50;
  15. 002C3617  mov         eax,dword ptr [pQ]  
  16. 002C361A  mov         dword ptr [eax],32h  
  17.      printf("q2 = %d\r\n",q);
  18. 002C3620  mov         esi,esp  
  19. 002C3622  push        3E8h  
  20. 002C3627  push        2CCCDCh  
  21. 002C362C  call        dword ptr ds:[2D045Ch]  
  22. 002C3632  add         esp,8  
  23. 002C3635  cmp         esi,esp  
  24. 002C3637  call        __RTC_CheckEsp (02C1325h)  
  25.      printf("pQ = %d\r\n",*pQ);
  26. 002C363C  mov         esi,esp  
  27. 002C363E  mov         eax,dword ptr [pQ]  
  28. 002C3641  mov         ecx,dword ptr [eax]  
  29. 002C3643  push        ecx  
  30. 002C3644  push        2CDAB8h  
  31. 002C3649  call        dword ptr ds:[2D045Ch]  
  32. 002C364F  add         esp,8  
  33. 002C3652  cmp         esi,esp  
  34. 002C3654  call        __RTC_CheckEsp (02C1325h)  
  35.      printf("q address:%d\r\n",&q);
  36. 002C3659  mov         esi,esp  
  37. 002C365B  lea         eax,[q]  
  38. 002C365E  push        eax  
  39. 002C365F  push        2CCC70h  
  40. 002C3664  call        dword ptr ds:[2D045Ch]  
  41. 002C366A  add         esp,8  
  42. 002C366D  cmp         esi,esp  
  43. 002C366F  call        __RTC_CheckEsp (02C1325h)  
  44.      printf("pQ address:%d\r\n",pQ);
  45. 002C3674  mov         esi,esp  
  46. 002C3676  mov         eax,dword ptr [pQ]  
  47. 002C3679  push        eax  
  48. 002C367A  push        2CDAC4h  
  49. 002C367F  call        dword ptr ds:[2D045Ch]  
  50. 002C3685  add         esp,8  
  51. 002C3688  cmp         esi,esp  
  52. 002C368A  call        __RTC_CheckEsp (02C1325h)  
复制代码

注:3E8h = 1000,32h = 50

由上面汇编代码可以看出.编译器把代码中的所有q都用3E8H代替了.也就是说 const定义的常量 在编译器生成阶段被替换成真实值了.所以无论你怎么修改const变量名所指的内存,其实都是没有用处的.因为在程序生成之后 所有的q 都被替换了.即使你在你的IDE编辑器中调试的时候看到q所指的是修改后的值50.


本文来自:http://shadowkong.com/archives/1845







欢迎光临 守望者--AIR技术交流 (http://www.airmyth.com/)