其实在汇编层面上,引用的代码和指针的代码是一致的。
先看指针情况下的代码分析,如下所示:
#include <iostream>
using namespace std;
void fuzhi(int *x)//引用传参
{
*x = 10;
}
int main(int argc, char** argv)
{
int a = 0;
int b;
a = 20;
fuzhi(&a);
return 0;
}
本人用的是vs2017编译器,先打断点如下:
注意本人打断点的位置,然后启动调试,然后打开反汇编窗口,如下图所示:
这里面的截图不清晰,本人现在只截右边汇编窗口的部分,如下所示:
可以看到,红色方框圈里来的有两部分,其中第一部分是栈帧大小的圈定,bp是栈底,sp是栈顶,由于栈是自顶向下生长,所以sp其实比bp小。里面的0DCh,其中字母h表示16进制,故0DCh是十进制的220,这就是目前main函数栈帧的大小,如果main函数中定义一个数组char szBuf[1000],则会发现这里面的0DCh要变成一个比较大的数字,肯定比1000大。
再看第二部分,这一部分其实是对栈帧空间进行初始化,初始化用到的数字就是0xCCCCCCCC。初始化的范围为37h(0x37),即55个四字节大小。共220个字节,现在调试下看看,鼠标放到汇编代码出,按F10执行下一步,F11是step in。
可以看到esp的值是17823592,变量a的值是7940691,16进制表示为0x792A53,esp的16进制表示为0x10FF768,然后打开内存窗口,输入0x10FF768
红色部分框住的就是a的值,可以看到cpu是小端模式,然后汇编代码接着F10,过初始化后,可以看到内存窗口大部分区域被初始化成了cc。此时a的值就是0xCCCCCCCC,很明显是一个负数,a = -858993460。
栈帧构建和初始化就讲到这里,后面看fuzhi(&a)处的汇编代码
fuzhi(&a);
007921B0 lea eax,[a]
007921B3 push eax
007921B4 call fuzhi (079140Bh)
007921B9 add esp,4
第一步,lea eax,[a]是指将a的地址赋给eax,第二部push eax,这步是参数压栈,而eax目前的值是a的地址,故压栈的参数就是a的地址。
如下所示:
F10到call这步,可以看到eax的值是17823808,16进制是10FF840,即a的地址。
然后按F11,进入到fuzhi函数的汇编代码处。
红色部分的3部分,第一部分是栈帧大小的开辟,第二部分是栈帧数据的初始化,第三部分是首先将x的值赋给eax,然后将0Ah,即数字10,赋给eax所指的内存单元,即x所指的内存单元。所以函数调用后,变量的值自然改变。
下面再看下引用代码的情况,代码如下:
#include <iostream>
using namespace std;
void fuzhi(int &x)//引用传参
{
x = 10;
}
int main(int argc, char** argv)
{
int a = 0;
int b;
a = 20;
fuzhi(a);
return 0;
}
如前面一样打断点,查看右边的汇编代码:
可以看到前面也是栈帧开辟和初始化,现在看main调用fuzhi这块调用汇编代码:
fuzhi(a);
007B21B0 lea eax,[a]
007B21B3 push eax
007B21B4 call fuzhi (07B1410h)
007B21B9 add esp,4
可以看出跟前面指针代码时的一摸一样。
然后调试到fuzhi代码的汇编处,可以看到,也是将10赋值给x的地址空间。