从汇编看c++中的引用和指针
添加时间:2013-5-5 点击量:
在c++中,引用和指针具有雷同的感化,都可以用来在函数里面给变函数外面对象或者变量的值,下面就来看他们的道理。
起首是引用景象下的c++源码:
void add(int a, int b, int&c) {
c = a + b;
}
int main() {
int a = 1;
int b = 2;
int c = 0;
add(a, b, c);
}
下面是main对应的汇编码:
; 6 : int main() {
push ebp
mov ebp, esp
sub esp, 12 ; 为该调用函数的栈空间预留12byte,用来存储局部变量a,b, c
; 7 : int a = 1;
mov DWORD PTR _a¥[ebp], 1;初始化a _a¥为a存储空间地址相对于ebp基址的偏移量
; 8 : int b = 2;
mov DWORD PTR _b¥[ebp], 2;初始化b _b¥为b存储空间地址相对于ebp基址的偏移量
; 9 : int c = 0;
mov DWORD PTR _c¥[ebp], 0;初试化c _c¥为c存储空间地址相对于ebp基址的偏移量
; 10 : add(a, b, c);
lea eax, DWORD PTR _c¥[ebp]; 获取c存储空间相对于ebp基址的偏移量(即c存储单位的偏移地址),放在存放器eax中
push eax;保存c存储空间的偏移量到客栈中
mov ecx, DWORD PTR _b¥[ebp];将b存储空间里面的值(即b的值)放在存放器ecx中
push ecx;保存b存储空间的值到客栈中
mov edx, DWORD PTR _a¥[ebp];将a存储空间里面的值(即a的值)放在存放器edx里面
push edx;保存a存储空间的到客栈
;上方push eax push ecx push edx在栈里面存储了本来局部变量a,b,c的值,只不过对于c来说,存储的是c存储空间的偏移地址
;是以,对于a,b来说,也就是将他们的值得一份拷贝存了起来,也就是传值;而c只是存储了本身存储空间的偏移地址,也就是传地址
call ?add@@YAXHHAAH@Z ; 调用add函数,上方的语句已经为传递参数做好了筹办
add esp, 12 ; 因为刚才为调用函数add传递参数进行了压栈,这里开释栈空间,即开释参数
;这就是为什么函数调用完成后局部变量和参数无效的原因,因为他们的空间被开释了
; 11 :
; 12 : }
xor eax, eax
mov esp, ebp
pop ebp
ret 0
下面是函数add对应的汇编码:
; 1 : void add(int a, int b, int&c) {
push ebp
mov ebp, esp
; 2 : c = a + b;
mov eax, DWORD PTR _a¥[ebp];取参数a的值到存放器eax中
add eax, DWORD PTR _b¥[ebp];取参数b的值与eax中a的值相加,成果放到eax中
mov ecx, DWORD PTR _c¥[ebp];去c的偏移地址放到存放器ecx中
mov DWORD PTR [ecx], eax;将eax中的成果写到由ecx指定的地址单位中去,即c地点存储单位
; 3 : }
pop ebp
ret 0
从上方可以看到,对于传值,c++确切传的是一份值拷贝,而对于引用,固然是传值的情势,然则其实编译器内部传递的是值得地址
下面是指针的景象的c++源码:
void add(int a, int b, int c) {
c = a + b;
}
int main() {
int a = 1;
int b = 2;
int c = 0;
add(a, b, &c);
}
mian函数对应的汇编码:
; 6 : int main() {
push ebp
mov ebp, esp
sub esp, 12 ;
; 7 : int a = 1;
mov DWORD PTR _a¥[ebp], 1
; 8 : int b = 2;
mov DWORD PTR _b¥[ebp], 2
; 9 : int c = 0;
mov DWORD PTR _c¥[ebp], 0
; 10 : add(a, b, &c);
lea eax, DWORD PTR _c¥[ebp]
push eax
mov ecx, DWORD PTR _b¥[ebp]
push ecx
mov edx, DWORD PTR _a¥[ebp]
push edx
call ?add@@YAXHHPAH@Z ; add
add esp, 12 ;
; 11 :
; 12 : }
xor eax, eax
mov esp, ebp
pop ebp
ret 0
add函数对应的汇编码:
; 1 : void add(int a, int b, int c) {
push ebp
mov ebp, esp
; 2 : c = a + b;
mov eax, DWORD PTR _a¥[ebp]
add eax, DWORD PTR _b¥[ebp]
mov ecx, DWORD PTR _c¥[ebp]
mov DWORD PTR [ecx], eax
; 3 : }
pop ebp
ret 0
可以看到,指针和引用的汇编码一样,是以两者的感化也一样
无论对感情还是对生活,“只要甜不要苦”都是任性而孩子气的,因为我们也不完美,我们也会伤害人。正因为我们都不完美,也因为生活从不是事事如意,所以对这些“瑕疵”的收纳才让我们对生活、对他人的爱变得日益真实而具体。—— 汪冰《世界再亏欠你,也要敢于拥抱幸福》
在c++中,引用和指针具有雷同的感化,都可以用来在函数里面给变函数外面对象或者变量的值,下面就来看他们的道理。
起首是引用景象下的c++源码:
void add(int a, int b, int&c) {
c = a + b;
}
int main() {
int a = 1;
int b = 2;
int c = 0;
add(a, b, c);
}
下面是main对应的汇编码:
; 6 : int main() {
push ebp
mov ebp, esp
sub esp, 12 ; 为该调用函数的栈空间预留12byte,用来存储局部变量a,b, c
; 7 : int a = 1;
mov DWORD PTR _a¥[ebp], 1;初始化a _a¥为a存储空间地址相对于ebp基址的偏移量
; 8 : int b = 2;
mov DWORD PTR _b¥[ebp], 2;初始化b _b¥为b存储空间地址相对于ebp基址的偏移量
; 9 : int c = 0;
mov DWORD PTR _c¥[ebp], 0;初试化c _c¥为c存储空间地址相对于ebp基址的偏移量
; 10 : add(a, b, c);
lea eax, DWORD PTR _c¥[ebp]; 获取c存储空间相对于ebp基址的偏移量(即c存储单位的偏移地址),放在存放器eax中
push eax;保存c存储空间的偏移量到客栈中
mov ecx, DWORD PTR _b¥[ebp];将b存储空间里面的值(即b的值)放在存放器ecx中
push ecx;保存b存储空间的值到客栈中
mov edx, DWORD PTR _a¥[ebp];将a存储空间里面的值(即a的值)放在存放器edx里面
push edx;保存a存储空间的到客栈
;上方push eax push ecx push edx在栈里面存储了本来局部变量a,b,c的值,只不过对于c来说,存储的是c存储空间的偏移地址
;是以,对于a,b来说,也就是将他们的值得一份拷贝存了起来,也就是传值;而c只是存储了本身存储空间的偏移地址,也就是传地址
call ?add@@YAXHHAAH@Z ; 调用add函数,上方的语句已经为传递参数做好了筹办
add esp, 12 ; 因为刚才为调用函数add传递参数进行了压栈,这里开释栈空间,即开释参数
;这就是为什么函数调用完成后局部变量和参数无效的原因,因为他们的空间被开释了
; 11 :
; 12 : }
xor eax, eax
mov esp, ebp
pop ebp
ret 0
下面是函数add对应的汇编码:
; 1 : void add(int a, int b, int&c) {
push ebp
mov ebp, esp
; 2 : c = a + b;
mov eax, DWORD PTR _a¥[ebp];取参数a的值到存放器eax中
add eax, DWORD PTR _b¥[ebp];取参数b的值与eax中a的值相加,成果放到eax中
mov ecx, DWORD PTR _c¥[ebp];去c的偏移地址放到存放器ecx中
mov DWORD PTR [ecx], eax;将eax中的成果写到由ecx指定的地址单位中去,即c地点存储单位
; 3 : }
pop ebp
ret 0
从上方可以看到,对于传值,c++确切传的是一份值拷贝,而对于引用,固然是传值的情势,然则其实编译器内部传递的是值得地址
下面是指针的景象的c++源码:
void add(int a, int b, int c) {
c = a + b;
}
int main() {
int a = 1;
int b = 2;
int c = 0;
add(a, b, &c);
}
mian函数对应的汇编码:
; 6 : int main() {
push ebp
mov ebp, esp
sub esp, 12 ;
; 7 : int a = 1;
mov DWORD PTR _a¥[ebp], 1
; 8 : int b = 2;
mov DWORD PTR _b¥[ebp], 2
; 9 : int c = 0;
mov DWORD PTR _c¥[ebp], 0
; 10 : add(a, b, &c);
lea eax, DWORD PTR _c¥[ebp]
push eax
mov ecx, DWORD PTR _b¥[ebp]
push ecx
mov edx, DWORD PTR _a¥[ebp]
push edx
call ?add@@YAXHHPAH@Z ; add
add esp, 12 ;
; 11 :
; 12 : }
xor eax, eax
mov esp, ebp
pop ebp
ret 0
add函数对应的汇编码:
; 1 : void add(int a, int b, int c) {
push ebp
mov ebp, esp
; 2 : c = a + b;
mov eax, DWORD PTR _a¥[ebp]
add eax, DWORD PTR _b¥[ebp]
mov ecx, DWORD PTR _c¥[ebp]
mov DWORD PTR [ecx], eax
; 3 : }
pop ebp
ret 0
可以看到,指针和引用的汇编码一样,是以两者的感化也一样
无论对感情还是对生活,“只要甜不要苦”都是任性而孩子气的,因为我们也不完美,我们也会伤害人。正因为我们都不完美,也因为生活从不是事事如意,所以对这些“瑕疵”的收纳才让我们对生活、对他人的爱变得日益真实而具体。—— 汪冰《世界再亏欠你,也要敢于拥抱幸福》