先看一段代码:

#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. Python I/O编程 --读写文件、StringIO/ BytesIO

    I/O编程 Input/Output  输入/输出 Stream(流)是一个很重要的概念,可以把流想象成一个水管,数据就是水管里的水 Input Stream就是数据从外面(磁盘.网络)流进内存,Ou ...

  2. 【JZOJ6232】【20190625】喜欢最最痛

    题目 \(n\)个节点的树,边权为正整数. 从1 号点开始走一个路径并最终回到 1 号点,且这条路径经过了所有的边. 一条路径的代价就是它经过的边的边权之和. 可以加若干条额外边,第 i 条加的额外边 ...

  3. Vue项目预渲染机制

    我们知道SPA有很多优点,不过一个缺点就是对(不是Google的)愚蠢的搜索引擎的SEO不友好,为了照顾这些引擎,目前主要有两个方案:服务端渲染(Server Side Rendering).预渲染( ...

  4. 你知道多少this,new,bind,call,apply?那我告诉你

    那么什么是this,new,bind,call,apply呢?这些你都用过吗?掌握这些内容都是基础中的基础了.如果你不了解,那还不赶快去复习复习,上网查阅资料啥的! 通过call,apply,bind ...

  5. Zookeeper循环注册监听器

    Zookeeper中的监听器只执行一次,需要在watcher类中重写process方法,以达到重复注册监听器的效果 /** * 连接zk服务器 * */ public static void conn ...

  6. mac下 Eclipse代码自动补齐 设置

    Eclipse -> Perferences -> Java -> Editor -> Content Assist如下图. 将auto activation triggers ...

  7. 5G 融合计费系统架构设计与实现(一)

    5G 融合计费系统架构设计与实现(一) 随着5G商用临近,5G的各个子系统也在加紧研发调试,本人有兴全程参与5G中的融合计费系统(CCS)的设计.开发.联调工作.接下来将用几篇文章介绍我们在CCS实现 ...

  8. kafka(二) 高性能技术分析

    参考文章: http://www.infoq.com/cn/articles/kafka-analysis-part-6 Partition提供并行处理的能力 Kafka是一个Pub-Sub的消息系统 ...

  9. Junit TDD

    参考链接:https://www.w3cschool.cn/junit/ 什么是 JUnit? JUnit 是一个 Java 编程语言的单元测试框架.JUnit 在测试驱动的开发方面有很重要的发展,是 ...

  10. Gaze Estimation学习笔记(2)-It's Written All Over Your Face Full-Face Appearance-Based Gaze Estimation

    目录 前言 将完整脸部图像作为输入的空间权重CNN方法 将full-face image作为输入的原因 加入空间权重的CNN方法 基础CNN结构 空间权重机制 实验及分析 头部姿态.面部表现视线方向的 ...