C++:在函数参数中使用++与–运算符

进行C++的学习有一段时间了,今天做练习的时候遇到了一个在函数参数中使用带有++运算符表达式的问题,稍微研究了一下发现用到的知识点还不少,挺有意思的,这里正好进行下总结扩展,顺便梳理一下最近学到的知识。由于递增运算符++与递减运算符–的机制完全一致,以下仅以++为例进行讨论,–同理。

问题

以下程序的运行结果是什么呢?

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

答案是4 4 43 2 1,有没有觉得意外呢?其实只要理解了++运算符的使用方式和C++的函数调用惯例,这个问题非常好解释。

递增运算符++

++是个神奇的一元运算符,根据它位置的不同,有前置版本和后置版本两种形式。虽然最终效果都是使变量进行自增1的运算,但是这这两种版本的返回值和执行机理却大不相同。假设我们有一个整形变量int i,根据《C++Primer》,前置版本与后置版本区别如下:

  • 前置版本++i:首先将运算对象加1,然后将改变后的对象作为求值结果。返回值为该对象的引用,为一个左值
  • 后置版本i++:首先保留一个运算对象的副本,然后将运算对象加1,并将副本作为求值结果。返回值为将对象加1之前的副本临时量,为一个右值

如此一来,数值的问题便可以解释了。

  • foo(++a, ++a, ++a)的每个实参位置的表达式都会使变量a递增1,同时返回对a的引用&a。实参位置上的三个++a计算完毕后有a=4,故最终传入foo的三个实参都为a的值4
  • foo(b++, b++, b++)的每个实参位置的表达式都会使变量b递增1,同时返回递增之前的值的临时量。因此第一次b++使b=2的同时将b加1之前的值1作为实参传入foo,第二次b++使b=3的同时将2传入foo,第三次b++使b=4的同时将3传入foo

问题似乎解决了,但是仔细想想还是有些奇怪:为什么foo(b++, b++, b++)的输出顺序是3 2 1呢?这说明我们实际调用的是foo(3, 2, 1),为什么会这样呢?要解释这个问题,那就要稍微提一下C++的函数调用惯例了。

函数调用惯例

这部分内容只做大致说明,不做详细讲解,详情可参阅《程序员的自我修养》。简单来说,为了正确调用函数,函数的调用方和被调用方对于函数如何调用需要有一个明确的约定,这样的约定就称为调用惯例。调用惯例规定了许多函数调用时的规则,其中有一项与我们的问题息息相关,那就是函数参数的传递顺序

C++默认的调用惯例是cdecl,它规定参数的传递顺序为从右至左压参数入栈。因此,foo(b++, b++, b++)实际上最先对最右边的b++表达式进行求值,然后处理中间的,最后处理最左边的,所以我们实际调用的是foo(3, 2, 1)

这下问题总算是彻底解决了。顺便,foo(++a, ++a, ++a)的顺序当然也是从右至左的,只不过最后实参都是&a,反映不出顺序的问题罢了。

*修订:编译器有权在不致错误的情况下重新排列同一个语句中各表达式的执行顺序,因此函数实参表达式的计算并不一定是严格从右至左的,参见《Effective C++》条款17。

再顺便复习一下引用的相关知识。因为++b返回的是一个临时量右值,普通引用是绑定不了的,因此如果foo的参数类型为int&b++这种后置递增表达式是不能当实参的。而因为常量引用具有能够绑定字面值的特殊性质,所以参数类型为const int&时可以用b++作为实参。

C++:在函数参数中使用++与--运算符相关推荐

  1. 函数参数中带省略号的用法

     [转]函数参数中带省略号的用法 本文摘自CDSN<可变参数学习笔记>,原帖链接:http://topic.csdn.net/t/20041124/09/3582660.html 前言 ...

  2. Python函数参数中的冒号与箭头

    在一些Python的工程项目中,我们会看到函数参数中会有冒号,有的函数后面会跟着一个箭头,你可能会疑惑,这些都是什么东西? 其实函数参数中的冒号是参数的类型建议符,告诉程序员希望传入的实参的类型.函数 ...

  3. python函数定义中参数列表里的参数是_python函数参数中的/和*是什么意思?

    在python3.8之后函数参数中允许出现/和*号,/用来指明某些函数形参必须使用位置参数而非关键字参数的形式,*出现在函数参数中第一种含义可以表示为可变参数,一般写作*args:对于单独出现在参数中 ...

  4. C++中WINAPI函数参数中的IN和OUT

    在C++API函数参数中的in和out其实是一个宏,其中,in这个变量或参数是输入值,即要求必须给这个变量填写好以后提交给某个函数去执行. out这个变量的意思是输出值,即你不需要预先给它赋值,当函数 ...

  5. 关于cmp函数参数中的符号(转)

    原文链接:https://blog.csdn.net/qie_wei/article/details/81135920 关于sort函数中的cmp函数有着不同的写法,以刚刚的整形元素比较为例 还有人是 ...

  6. C函数参数中的三个点

    原文链接一:http://hi.baidu.com/wjun520/blog/item/1678a11da07fe68086d6b653.html C++中有函数重载这种方法,以供我们调用时要可以不确 ...

  7. java中3|4_关于java:函数参数中3个点的含义是什么?

    本问题已经有最佳答案,请猛点这里访问. 我在读Android文档中的AsyncTask. private class DownloadFilesTask extends AsyncTask { pro ...

  8. 函数参数中的3个点表示什么

    转载于网友的一片文章,写的很好! 标准库提供的一些参数的数目可以有变化的函数.例如我们很熟悉的printf,它需要有一个格式串,还应根据需要为它提供任意多个"其他参数".这种函数被 ...

  9. python教程:函数参数中默认值及重要警告

    最有用的形式是对一个或多个参数指定一个默认值.这样创建的函数,可以用比定义时允许的更少的参数调用,比如: def ask_ok(prompt, retries=4, reminder='Please ...

最新文章

  1. Linux 网络管理(1) - 网络配置文件
  2. windows8.1 windows defender service无法启动解决方案
  3. 阿里钉钉,马云旗下的又一个千亿美金产品?
  4. 【Python】如何学好Python
  5. 【阿里云课程】图神经网络基础:图的应用、表示与图卷积
  6. jsp项目放入宝塔windows环境_《鸡站群组》-教你建站(1.1) 下载并配置windows宝塔面板...
  7. 每日一笑 | 坐牢吗?学编程那种~
  8. HDU5877 - Weak Pair
  9. 【youcans 的 OpenCV 例程200篇】135. 形态学重建之粒度测定
  10. 《海外社交媒体营销》一一2.2 根据你的公司特点,制订适合自己的营销计划...
  11. 【译】Simple MySQL ORM for C
  12. 0084-CYX的异己
  13. 数字超材料uv坐标matlab,基于数字编码超材料和压缩感知的实孔径雷达成像方法与流程...
  14. BOS v2.0后台管理系统 JQuery Easyui 相关知识讲解
  15. CAXA实体设计 2020相对其他3D软件的优势有哪些?
  16. ZYNQ图像处理(2)——ov5640_hdmi显示环境搭建
  17. Tims中国上市背后:以新流派打法,“开源”咖啡市场
  18. 惠普m227fdw引擎通信错误_惠普打印机HPM227提示耗材余量错误怎么办?
  19. 使用ESP8266和MPU6050制作倾斜角度监控器
  20. 不仅仅是土豆_设计成功不仅仅需要设计技能

热门文章

  1. 世界观测最佳点南极:极点条件构成地舆乐土
  2. Python调用笔记本摄像头,并实现人脸检测功能
  3. openstack中的quota
  4. 迭代与递归的区别(斐波那契数列和小猴子摘桃)
  5. 记录一下.NET Core Flurl的Post各种用法
  6. python实现洗牌算法_python-洗牌算法的实现
  7. bat一键修改Windows远程桌面端口
  8. 新手学习eclipse使用
  9. L1-024 后天 Python
  10. html2canvas的使用方法,html2Canvas使用总结