1. #include<iostream>
  2. #include<stdlib.h>
  3. using namespace std;
  4. const int &add( const int &a,const int &b)
  5. {
  6. return a+b;
  7. }
  8. int main()
  9. {
  10. const int &result = add(5,8);
  11. add(11, 8);//重复使用栈.排除虽然栈回收.但值没变的可能性
  12. add(5, 8);
  13. add(5,8);
  14. add(5,8);
  15. add(5,8);
  16. cout << result << endl;
  17. system("pause");
  18. return 0;
  19. }
   

以上结果输出13.原因在于当add的时候参数5,8.将生成2个临时对象(但这个临时对象的生存周期可伴随main).用来保存5,8
main.c 部分反汇编代码
  1. 00FC18CE mov dword ptr [ebp-0D4h],8 ;创建一个地址用来保存8
  2. 00FC18D8 mov dword ptr [ebp-0E0h],5 ;创建一个地址用来保存5
  3. 00FC18E2 lea eax,[ebp-0D4h] ;将保存8的地址赋给eax.
  4. 00FC18E8 push eax ;地址压栈
  5. 00FC18E9 lea ecx,[ebp-0E0h] ;将保存5的地址赋给ecx
  6. 00FC18EF push ecx ;将地址压入栈中
  7. 00FC18F0 call add (0FC138Eh)
  8. 00FC18F5 add esp,8 ;回收栈
  9. 00FC18F8 mov dword ptr [result],eax 

  1. const int &add(const int &a, const int &b)
  2. {
  3. 002217C0 push ebp
  4. 002217C1 mov ebp,esp
  5. 002217C3 sub esp,0CCh ;开辟局部栈空间,大小为0cch
  6. 002217C9 push ebx
  7. 002217CA push esi
  8. 002217CB push edi
  9. 002217CC lea edi,[ebp-0CCh] ;
  10. 002217D2 mov ecx,33h
  11. 002217D7 mov eax,0CCCCCCCCh
  12. 002217DC rep stos dword ptr es:[edi]
注意.以上局部栈空间大小在 esp到esp-0cch之间.当函数调用完此空间将回收(并不是真正意义的回收.只是改变栈指针罢了.原来的数值还在.不过如果此栈被反复调用(这就是为何我重复调用的原因).栈的数据当然改变)
  1. 00FC17DE mov eax,dword ptr [a] ;将临时对象5的地址赋给eax (const int &a) [a]保存的是临时对象5的
  2. 00FC17E1 mov ecx,dword ptr [eax] ;将eax保存的值给ecx
  3. 00FC17E3 mov edx,dword ptr [b] ;将临时对象b的地址赋给edx
  4. 00FC17E6 add ecx,dword ptr [edx] ;将edx保存的值加到ecx中
  5. 00FC17E8 mov dword ptr [ebp-0C8h],ecx ;将结果保存到ebp-0c8h中(临时对象)
  6. 00FC17EE lea eax,[ebp-0C8h] ;将结果地址赋给eax
  7. }
  8. 执行完Add函数后将临时对象的地址保存到result引用中
  9. 00FC18F8 mov dword ptr [result],eax 
注意了 return a+b;开辟的临时对象在ebp-0c8h处.处于局部栈之内!!!(ebp~ebp-0xcch).当add调用完后..将此回收地址赋给了result引用.于是出现了结果乱了的情况了

2.初始化一个常量引用所引发的临时对象
  当初始化一个常量引用(const reference)时,如果给定的初始化对象类型与目标引用类型不同(但是两者  能够相互转换),需要产生临时对象;
对于局部const int  temp=10这类变量.即使取地址使得其改变也不会有任何变化.
double db=10.000;
int &q=db;
以上会报错.
因为实际他会转化为 int temp=(int) db; int &a=temp;.本意是想通过a可以改变db.但实现却不可以改变(改变的是Temp).因此.编译器将会报错

当然如果是 const int &a=db;这样编译器将不会报错.因为const修饰这个temp(db)不会改变的
  1. double db = 10;
  2. 00EB1868 movsd xmm0,mmword ptr ds:[0EB6B38h]
  3. 00EB1870 movsd mmword ptr [db],xmm0
  4. const int &q = db;
  5. 00EB1875 cvttsd2si eax,mmword ptr [db] ;db的值10赋给eax
  6. 00EB187A mov dword ptr [ebp-28h],eax ;将eax赋给ebp-28h(就是临时对象)
  7. 00EB187D lea ecx,[ebp-28h]
  8. 00EB1880 mov dword ptr [q],ecx


3.修改const 常量的值
  1. #include<iostream>
  2. #include<stdlib.h>
  3. using namespace std;
  4. const int &add(const int &a, const int &b)
  5. {
  6. return a + b;
  7. }
  8. int main()
  9. {
  10. const int temp = 10;
  11. int *p = (int *)&temp;
  12. *p = 10000;
  13. cout << *p << endl;
  14. cout << temp << endl;
  15. system("pause");
  16. }

以上*p输出10000,但是temp输出10;因为const int temp=10在编译阶段就已经知道其值了
  1. cout << temp << endl;
  2. 002C4F91 push 2C1069h
  3. 002C4F96 mov edi,esp
  4. 002C4F98 push 0Ah ;将10压栈进行输出.所以..反正汇编语言是这样解释的..那就是编译器的规则了
  5. 002C4F9A mov ecx,dword ptr ds:[2CA0A8h]
  6. 002C4FA0 call dword ptr ds:[2CA0A0h]




最简单程序
  1. #include<iostream>
  2. #include<stdlib.h>
  3. using namespace std;
  4. int main()
  5. {
  6. const int &p = 1;
  7. system("pause");
  8. }
常量引用也会分配变量内存的.引用一个常量将会产生一个临时对象.临时对象赋值为1.然后将临时对象地址赋给引用.引用的底层实现其实也是一个指针常量罢了
  1. const int &p = 1;
  2. 002618E8 mov dword ptr [ebp-18h],1 ;ebp-18h是临时对象.将1赋给临时对象
  3. 002618EF lea eax,[ebp-18h] ;取出临时对象的地址
  4. 002618F2 mov dword ptr [p],eax ;将地址赋给p










反汇编角度->C++ const的更多相关文章

  1. 从汇编的角度看待const与#define

    先观察一下的代码: #include<stdio.h> int main(){ ; int y; int *pi=(int*)&i; *pi=; y=*pi; int tempi; ...

  2. 反汇编看c++引用

    继续反汇编系列,本次使用vc2008在x86体系下分析c++中的引用. 定义一个引用类型和将一个变量转换成引用类型一样吗? 引用比指针安全,真的是这样吗,对引用不理解的话比指针还危险. 为什么要用常量 ...

  3. typedef,static,const用法

    一.typedef主要功能是定义一个已存在类型的别名,但是和宏并存 宏与typedef区别 1.宏定义只是简单的字符串替换 2.typedef定义的类型是类型的别名,typedef后面是一个整体声明, ...

  4. 零基础逆向工程13_C语言07_指针01_反汇编

    1."带*类型"的特征探测 宽度 在同一个平台下,任何指针变量的尺寸都是一样的(都等于系统字长),如在32位平台中任何类型指针宽度都是32位. 声明 1.带有* 的变量类型的标准写 ...

  5. CAD图在线Web测量工具代码实现(测量距离、面积、角度等)

    CAD如今在各个领域均得到了普遍的应用并大大提高了工程技术人员的工作效率.在桌面端,AutoCAD测量工具已经非常强大:然后在Web端,如何准确.快速的对CAD图在Web进行测量呢? 功能 能Web在 ...

  6. (转)Windows驱动编程基础教程

    版权声明     本书是免费电子书. 作者保留一切权利.但在保证本书完整性(包括版权声明.前言.正文内容.后记.以及作者的信息),并不增删.改变其中任何文字内容的前提下,欢迎任何读者 以任何形式(包括 ...

  7. 【HEVC】4、HM-16.7编码一个CU(帧内部分) 3.帧内预测各种模式实现

    HEVC中一共定义了35中帧内编码预测模式,编号分别以0-34定义.其中模式0定义为平面模式(INTRA_PLANAR),模式1定义为均值模式(INTRA_DC),模式2~34定义为角度预测模式(IN ...

  8. 仿造slither.io第一步:先画条蛇

    前言 最近 slither.io 貌似特别火,中午的时候,同事们都在玩,包括我自己也是玩的不亦乐乎. 好久好久没折腾过canvas相关的我也是觉得是时候再折腾一番啦,所以就试着仿造一下吧.楼主也没写过 ...

  9. 网站启动SSL, http变为https后,session验证码错误解决方法

    网站启动SSL, http变为https后,session验证码错误解决方法   最近公司需要后台启动安全证书,证书安装完毕后,后台老提示 验证码错误,经过几天的研究,此问题已经得到有效解决,现把方法 ...

随机推荐

  1. 深入理解 hashcode 和 hash 算法

    深入理解 hashcode 和 hash 算法 2017年12月30日 23:06:07 阅读数:5197 标签: hashhashmaphashcode二进制 更多 个人分类: jdk-源码  ht ...

  2. spring boot yaml 自定义配置 映射到 java POJO

    只需要一个注解就ok: @ConfigurationProperties("user.other") “user.other” 这个值匹配的是user下的other对象 yaml ...

  3. day 35 补充

      MySQL数据库初识   MySQL数据库 本节目录 一 数据库概述 二 MySQL介绍 三 MySQL的下载安装.简单应用及目录介绍 四 root用户密码设置及忘记密码的解决方案 五 修改字符集 ...

  4. Python模块(三)(正则,re,模块与包)

    1. 正则表达式 匹配字符串 元字符 .   除了换行 \w  数字, 字母, 下划线 \d  数字 \s  空白符 \n 换行符 \t  制表符 \b  单词的边界 \W  \D \S 非xxx [ ...

  5. POJ:3228-Gold Transportation(要求最小生成树最大边最小)

    Gold Transportation Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 3079 Accepted: 1101 D ...

  6. 20188472 https://www.cnblogs.com/chenzg90826/

    我是一名学计算机的大一学生,对学计算机比较感兴趣,但是对于计算机的了解程度还不够深,所以我在这方面还只是一个初学者.经过了一个学期对计算机和编程语言的学习,我觉得要真正的学好这门专业真的还要更努力.在 ...

  7. Hive学习笔记(四)-- hive的桶表

    桶表抽样查询 查看hdfs上对应的文件内容 一个两个桶,第一个桶和第三个桶的数据 task = 4 4 / 2 = 2,一共是两个桶 第1个桶,第1+2个桶

  8. 记一次WMS的系统改造(3)— 行进中的复盘

    行进中的波折 革新总会面对一些阻力和风险,一种新的观念.一种新的模式要来替代既有的产品,从来都不是一件简单的事,在WMS改造这件事上我们一开始就提出两种概念货物驱动和任务驱动,并找到一个标杆产品Sla ...

  9. Selenium WebDriver- actionchians模拟鼠标悬停操作

    #encoding=utf-8 import unittest import time from selenium import webdriver from selenium.webdriver i ...

  10. Django 中CSRF中间件 'django.middleware.csrf.CsrfViewMiddleware',

    1.Django中CSRF中间件的工作原理及form表单提交需要添加{% csrf_token %}防止出现403错误 CSRF # 表示django全局发送post请求均需要字符串验证功能:防止跨站 ...