void main() {
int x = 1;
int& ref = x;
ref = 2;
printf("%d \n", ref);
return;
}
反汇编代码:
int x = 1;
00724A5F C7 45 F4 01 00 00 00 mov dword ptr [x],1
int& ref = x;
00724A66 8D 45 F4 lea eax,[x]
00724A69 89 45 E8 mov dword ptr [ref],eax
ref = 2;
00724A6C 8B 45 E8 mov eax,dword ptr [ref]
00724A6F C7 00 02 00 00 00 mov dword ptr [eax],2
printf("%d \n", ref);
00724A75 8B 45 E8 mov eax,dword ptr [ref]
00724A78 8B 08 mov ecx,dword ptr [eax]
00724A7A 51 push ecx
00724A7B 68 30 7B 72 00 push offset string "%d \n" (0727B30h)
00724A80 E8 4D C6 FF FF call _printf (07210D2h)
00724A85 83 C4 08 add esp,8
修改为指针,看看反汇编结果:
void main() {
int x = 1;
int* ref = &x;
*ref = 2;
printf("%d \n", *ref);
return;
}
是不是发现下面的反汇编结果和上面引用的一模一样!
int x = 1;
00B44A5F C7 45 F4 01 00 00 00 mov dword ptr [x],1
int* ref = &x;
00B44A66 8D 45 F4 lea eax,[x]
00B44A69 89 45 E8 mov dword ptr [ref],eax
*ref = 2;
00B44A6C 8B 45 E8 mov eax,dword ptr [ref]
00B44A6F C7 00 02 00 00 00 mov dword ptr [eax],2
printf("%d \n", *ref);
00B44A75 8B 45 E8 mov eax,dword ptr [ref]
00B44A78 8B 08 mov ecx,dword ptr [eax]
00B44A7A 51 push ecx
00B44A7B 68 30 7B B4 00 push offset string "%d \n" (0B47B30h)
00B44A80 E8 4D C6 FF FF call _printf (0B410D2h)
00B44A85 83 C4 08 add esp,8
引用类型
引用类型就是变量的别名,其在初始化时必须要赋值。
// 基本类型
int x = 1;
int& ref = x;
ref = 2;
printf("%d \n",ref);
// 类
Person p;
Person& ref = p;
ref.x = 10;
printf("%d \n",p.x);
// 指针类型
int****** x = (int******)1;
int******& ref = x;
ref = (int******)2;
printf("%d \n",x);
// 数组类型
int arr[] = {1,2,3};
int (&p)[3] = arr;
p[0] = 4;
printf("%d \n",arr[0]);
如上是引用类型作用在各个类型下的例子,那么引用类型是如何实现的呢?其本质是什么?我们可以看下反汇编代码:
会发现这段反汇编和指针的反汇编一模一样的:
这时候我们暂时的出结论:引用类型就是指针。
在我vs2022里实验下:
但如果引用类型就是指针,为什么C++需要新创建一个引用类型的概念呢?它们之间必然存在着一些区别,我们可以从初始化、运算、赋值来看反汇编代码的区别:
我们可以很清晰的看见区别从运算到赋值都不一样,指针运算到赋值改变的是指针本身,而不是指针指向的那个地址,而引用则不一样其从运算到赋值改变的是所引用的变量,我们得出这几个结论:
- 引用必须赋初始值,且只能指向一个变量,从一而终(专一);
- 对引用赋值,是对其指向的变量赋值,而不是修改引用本身的值;
- 对引用做运算,就是对其指向的变量做运算,而不是对引用本身做运算;
- 引用类型就是一个弱化了的指针;个人理解:引用类型就是一个*p。
C++设计引用类型是因为指针类型很难驾驭,一旦用不好就回出问题,所以取长补短设计了引用类型。
那么引用类型在实际开发中的作用是什么呢?我们可以用在函数参数传递中:
#include <stdio.h>
void Plus(int& i) {
i++;
return;
}
void main() {
int i = 10;
Plus(i);
printf("%d \n", i);
return;
}
如上代码中Plus函数的参数是一个引用类型,当我们把变量i传递进去,i就会自增1,而实际上也就修改变量i本身的值;换一种说法就是,我们之前函数参数传递的是值,而这里传递的是变量的地址。
那么在构造类型中又是怎么样的呢?
#include <stdio.h>
class Base {
public:
int x;
int y;
Base(int a, int b) {
this->x = a;
this->y = b;
}
};
void PrintByRef(Base& refb, Base* pb) {
printf("%d %d \n", pb->x, pb->y);
printf("%d %d \n", refb.x, refb.y);
}
void main() {
Base b(1, 2);
PrintByRef(b, &b);
return;
}
我们可以看见除了读取的表现形式不一样,实际上汇编代码是一模一样的;但是指针类型是可以重新赋值并运算的,而引用类型不可以。
当一个变量是int类型的,而我们引用类型却是一个其他类型的,会怎么样呢?
int x = 10;
Person& ref = (Person&)x;
这是可以编译的,但是没有实际意义,所以在使用引用的时候原来是什么类型就应该使用什么类型。
大家都知道,我们使用指针的时候是可以修改指针本身的,这会存在一定的风险,而C++中提供了引用类型,不可以修改引用本身,我们可以修改被引用的值,当我们不想其他人修改引用类型对应引用的值,可以使用const这个关键词,这种方式我们称之为常引用:
标签:逆向,00,int,C++,引用,printf,类型,ref From: https://blog.51cto.com/u_11908275/6941572