先看一段代码:

#include<iostream>
using namespace std; void func(int a, int b)
{
cout << a << " " << b << endl;
} int main()
{
int a = 0;
func(a++, ++a);
return 0;
}

由于C++是从右向左入栈(与编译器的调用约定有关,不是C++标准的规定),所以刚看到代码的时候,我以为结果会是“1 1”(先将++a入栈,再将a++入栈),然而事实是: 。这是在VS上面运行的,在g++上也是一样的结果。幸好VS还可以查看汇编代码。



由于在VS上有十分方便的反汇编工具,所以接下来说的东西都基于VS2019自带的反汇编。

设置断点并调试,便可以打开反汇编窗口:





下面这段就是在调用func函数时的汇编代码:

mov         eax,dword ptr [a]
add eax,1
mov dword ptr [a],eax //这三行指令将a+1
mov ecx,dword ptr [a]
mov dword ptr [ebp-0D0h],ecx //这两行指令将a的值存储到一个临时地址(寄存器间接寻址)中
mov edx,dword ptr [a]
add edx,1
mov dword ptr [a],edx /这三行指令又将a+1
mov eax,dword ptr [a]
push eax //这两行指令将a压入栈
mov ecx,dword ptr [ebp-0D0h]
push ecx //这两行指令将刚刚存储的临时地址的值压入栈 call func (0A312E9h) //调用func函数
add esp,8 //esp为栈指针寄存器

如果将代码改成

func(++a, ++a);

会是什么结果呢?答案是

mov         eax,dword ptr [a]
add eax,1
mov dword ptr [a],eax //这三行指令将a+1
mov ecx,dword ptr [a]
add ecx,1
mov dword ptr [a],ecx //这三行指令将a+1
mov edx,dword ptr [a]
push edx //这两行指令将a压入栈
mov eax,dword ptr [a]
push eax //这两行指令将a压入栈 call func (09912E9h)
add esp,8

可以看到,将a++改成++a之后,指令少了将a的值保存起来的步骤,并且由于并非在读取参数时就压入栈,而是在所有参数的表达式执行完之后才压入,所以最后压入参数栈的都是最后的变量a。

那么结合汇编代码就不难理解文章开头为什么是“1 2”了,基本就是这样的区别(注意:读取参数和执行参数的表达式时也是从右往左的)



在调用函数的时候,参数要避免使用自增和自减,避免出现混乱。



文章为作者结合个人理解编写,可能会有错漏的地方,如有错误,敬请指正。

a++与++a,谈谈C++的参数传递的更多相关文章

  1. 谈谈Delphi中的类和对象1---介绍几个概念 && 对象是一个地地道道的指针

    参考:http://blog.163.com/liang_liu99/blog/static/88415216200952123412180/ 以下的介绍主要针对的是Delphi的面向对象的知识,可能 ...

  2. 漫谈C指针:参数传递的三道题目

    漫谈C指针:参数传递的三道题目 2009-07-02 开讲之前,我先请你做三道题目.(嘿嘿,得先把你的头脑搞昏才行……唉呀,谁扔我鸡蛋?) 考题一,程序代码如下: [c] view plaincopy ...

  3. C语言的参数传递

    一.三道考题 开讲之前,我先请你做三道题目.(嘿嘿,得先把你的头脑搞昏才行……唉呀,谁扔我鸡蛋?) 考题一,程序代码如下:void Exchg1(int x, int y){   int tmp;  ...

  4. [转]谈谈关于MVP模式中V-P交互问题

    在差不多两年的时间内,我们项目组几十来号人都扑在一个项目上面.这是一个基于微软SCSF(Smart Client Software Factory)的项目,客户端是墨尔本一家事业单位.前两周,我奉命负 ...

  5. 《windows核心编程系列》十九谈谈使用远程线程来注入DLL。

    windows内的各个进程有各自的地址空间.它们相互独立互不干扰保证了系统的安全性.但是windows也为调试器或是其他工具设计了一些函数,这些函数可以让一个进程对另一个进程进行操作.虽然他们是为调试 ...

  6. 谈谈Spring中的BeanPostProcessor接口

    一.前言   这几天正在复习Spring的相关内容,在了解bean的生命周期的时候,发现其中涉及到一个特殊的接口--BeanPostProcessor接口.由于网上没有找到比较好的博客,所有最后花了好 ...

  7. 【原】谈谈对Objective-C中代理模式的误解

    [原]谈谈对Objective-C中代理模式的误解 本文转载请注明出处 —— polobymulberry-博客园 1. 前言 这篇文章主要是对代理模式和委托模式进行了对比,个人认为Objective ...

  8. 谈谈一些有趣的CSS题目(十二)-- 你该知道的字体 font-family

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

  9. 谈谈一些有趣的CSS题目(十一)-- reset.css 知多少?

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

随机推荐

  1. 使用jpillora/dnsmasq 提供可视化管理的dns server

    实际开发中dns 是一个比较重要的组件,一般大家可能会选择使用dnsmasq 但是缺少UI可视化,有些人可能会选择powerdns jpillora/dnsmasq 是一个对于dnsmasq 的包装, ...

  2. [Beta]Scrum Meeting#3

    github 本次会议项目由PM召开,时间为5月8日晚上10点30分 时长15分钟 任务表格 人员 昨日工作 下一步工作 木鬼 撰写博客整理文档 撰写博客整理文档 swoip 改进界面 改进界面 bh ...

  3. Nexus Repository Manager OSS 3.x 安装配置

    前言想要使用maven搭建项目,但是国内的网络环境可以想象,还有公司自己开发的jar包等问题,所以需要搭建一个maven的私服,这样便于管理. 找了一些教程,顺便记下来,当做笔记. 本文以Window ...

  4. 【转】SQL2008 链接Oracle 调用存储过程

    1. SQL链接ORACLE 都是可视化的操作 如下图: 红色框选的是oracle的数据驱动,如果没有这个驱动 那需要单独安装oracle的client端 装完以后就有了. 2.在创建之前,在SQLS ...

  5. QT自定义信号和槽

    最近项目中使用到QT,在此记录一下QT的核心,信号与槽: QObject::connect(const QObject *sender, const char *signal, const QObje ...

  6. [转]理解Vuex的辅助函数mapState, mapActions, mapMutations用法

    原文地址:https://www.cnblogs.com/tugenhua0707/p/9794423.html 在讲解这些属性之前,假如我们项目的目录的结构如下: ### 目录结构如下: demo1 ...

  7. php-7.3.4 configure: error: Please reinstall the libzip distribution

    php-7.3.4 configure: error: Please reinstall the libzip distribution # wget https://libzip.org/downl ...

  8. WebRTC搭建前端视频聊天室——信令篇

    这篇文章讲述了WebRTC中所涉及的信令交换以及聊天室中的信令交换,主要内容来自WebRTC in the real world: STUN, TURN and signaling,我在这里提取出的一 ...

  9. Fiddler抓包Fiddler过滤

    1.User Fiters启用 2.Action Action:Run Filterset now是否运行,Load Filterset加载,Save Filterset保存: 3.Hosts过滤 Z ...

  10. return & exit . in GO

    return结束当前函数,并返回指定值runtime.Goexit结束当前goroutine,其他的goroutine不受影响,主程序也一样继续运行os.Exit会结束当前程序,不管你三七二十一