zoukankan      html  css  js  c++  java
  • C/C++函数参数读取顺序

    说到C/C++函数参数读取顺序,很多人都知道在入栈时是从右至左的,可是真的有那么简单吗?先看一个例子:

    1 #include <cstdio>
    2 
    3 int main() {
    4     int a = 10;
    5     printf("%d %d %d
    ", a++, ++a, a);
    6     return 0;
    7 }

    按照从右向左读取,想当然的结果应该是:11 11 10,执行后a = 12。可是真的是这样吗?写个程序验证一下吧,于是就得到了下面的结果:

    很奇怪,这是为什么呢?要搞清楚什么情况恐怕得从汇编代码入手,那我们就看一下汇编代码喽:

         通过查看汇编代码,我们发现在参数入栈时顺序的确是从右向左入栈,但是在入栈前先把参数列表里的表达式算一遍得到表达式的结果,最后再把这些运算结果统一入栈,这就解释了为什么第三个参数a会输出12,因为执行完a, ++a, a++后a = 12。那为什么第一项++a会输出11呢,这就要看C++中的++运算符的实现机制了,通过上面的汇编代码,可以看到:

    ++a对应的是: addl $0x1, 0x1c(%esp)

    也就是说直接执行a+1;

    a++对应的是: mov 0x1c(%esp), %eax

                         addl $0x1, 0x1c(%esp)  

    先把执行到此时的a的值备份到%eax,然后再执行+1操作,所有的表达式都执行完了,该将参数入栈了。怎么入呢?

    不管是a,还是++a,入栈的代码都是:mov  0x1c(%esp), %edx

                                                      mov  %edx,0xc(&esp) | mov  %edx,0x8(&esp)

    也就是说直接从变量a所在的内存地址中取值。所以得到的肯定是所有运算都执行完的结果,也就是12。

    而a++的入栈代码是:mov %eax,0x4(&esp)

    直接把之前备份的值入栈了,而备份的时候a所在地址中保存的值是11,所以%eax中的值是11。

    这样一来是不是就说通了。

    总结下来有两点:

    1. 在将参数入栈前,编译器会先把参数的的表达式都处理掉,哪怕这些运算会改变其中某些参数的值,

    2.对于a++操作,编译器会开辟一个缓冲区来保存当前a的值,然后再对a操作,取值时是从缓冲区取,而不是直接从a的内存地址里取。

    最后再验证一下理论,a = 10, printf("%d %d %d %d ", a++, ++a, a, a++),结果应该是:12 13 13 10!

    哦耶!对了,撒花!

    好吧,参数列表中表达式的计算顺序并没有在C/C++中明确定义,每个编译器可以自由发挥,有自己的实现。没有给定编译环境的话结果是未知的,不过至少最新版的g++与msvs2013的实现是一致的。

  • 相关阅读:
    再看数据库——(1)存储过程
    Android nomedia 避免图片等资源泄露在系统图库其中
    南邮JAVA程序设计实验1 综合图形界面程序设计
    【零基础入门学习Python笔记013】元祖:戴上了枷锁的列表
    关于部门后端所有转向java前初步设想
    Windows环境下msysgit安装git flow
    UI_UISlider控件
    名不符实的读写锁
    js+ canvas 实现人物走动
    Android HandlerThread 源代码分析
  • 原文地址:https://www.cnblogs.com/easonliu/p/4224120.html
Copyright © 2011-2022 走看看