引用变量是c++引入的重要机制。
错误观念:引用本质只是别名,在符号表中ri和i对应于相同的变量地址
int i=5;
0100437E mov dword ptr [i],5
int &ri=i;
01004385 lea eax,[i]
01004388 mov dword ptr [ri],eax
ri=8;
0100438B mov eax,dword ptr [ri]
ri=8;
0100438E mov dword ptr [eax],8
在底层实现上,引用是用指针常量实现的,如果用指针常量实现,反汇编是一毛一样的。引用和指针常量关系如下:
(1)内存中占用都是4字节,存放都是被引用对象的地址,都必须在定义的同时进行初始化。
(2)指针常量本身允许寻址;引用变量不允许寻址,&r返回的是被引用对象的地址,就是变量r中的值,而不是变量r的地址,r的地址由编译器掌握,程序猿无法直接对其进行存取。
(3)凡用引用的代码,都可以用指针常量实现;反之不然,因为引用本身限制较多,不能完成指针所有的操作。
例如下面的代码是合法的:
int i=5,j=6;
int *const array[] = {&i,&j}; //指针数组
但是如下代码却是非法的:
int i=5,j=6;
int &array[] = {i,j}; //不可能有引用的数组
虽然引用在初始化时会绑定一个变量,不过也是可以有特殊手段可以改变引用绑定关系:
int main()
{
//freopen("input.txt","r",stdin);\
int i=5,j=6;
int &r = i;
void *pi = &i,*pj = &j;
int* addr;
int dis = (int)pj-(int)pi;
addr = (int *)((int)pj+dis); //精确计算r的地址
cout<<"&i == "; PRINT(pi); //i的地址
cout<<"&j == "; PRINT(pj); //j的地址
cout<<"&pi == "; PRINT(&pi); //pi的地址
cout<<"&pj == "; PRINT(&pj); //pj的地址
cout<<"dis == "; PRINT(dis);
PRINT(*addr);
//(*add)+=dis;
(*addr)=(int)&j; PRINT(*addr); //将r指向j
r=666;
cout<<"i == "; PRINT(i);
cout<<"j == "; PRINT(j);
return 0;
}
答案输出:
&i == 003CF9D0
&j == 003CF9C4
&pi == 003CF9AC
&pj == 003CF9A0
dis == -12
3996112
3996100
i == 5
j == 666
因为在内存中排布方式是:
dis 低地址
addr
pj
pi
r
j
i 高地址
在
&j == 003CF9C4
&pi == 003CF9AC
中隔了2个dis,其实就是夹了一个r