有没有办法找到引用的地址?
更具体地说,是变量本身的地址而不是它初始化的变量的地址。
有没有办法找到引用的地址?
更具体地说,是变量本身的地址而不是它初始化的变量的地址。
引用没有自己的地址。虽然引用可以作为指针来实现,但没有这种需要或保证。
C++ FAQ最好地解释了它:
与指针不同,一旦引用绑定到对象上,就不能将其“重新绑定”到另一个对象上。 引用本身不是对象(它没有标识;获取引用的地址会给您引用对象的地址;请记住:引用就是引用对象)。
还请参见我的答案,以获取有关引用与指针之间区别的全面列表。
引用就是引用对象本身
va_start(vargs,a_referece_argument)
。 :( - Mordachaiva_start
的第二个参数如果是引用类型就会导致未定义行为。 - Lightness Races in Orbit不行。没有办法获取一个引用的地址。
那是因为一个引用不是一个对象,它只是一个别名(也就是说它是另一个对象的名称)。
int x = 5;
int& y = x;
std::cout << &x << " : " << &y << "\n";
这将打印出相同的地址。
这是因为 'y' 只是对象 'x' 的另一个名称(别名)。
ISO标准说得最好:
不得引用引用,不得使用引用数组和指向引用的指针。
我不太喜欢很多人在这里使用的逻辑,即因为引用“不能保证只是一个指针”,所以你不能这样做。就像 int x
可能只是一个处理器寄存器而没有地址,但是当使用 &x
时,它会神奇地变成一个内存位置,编译器仍然可能允许你想要的东西。
过去,许多编译器确实允许您完全做到这一点,例如:
int x, y;
int &r = x;
&r = &y; // use address as an lvalue; assign a new referent
我刚刚检查了一下,GCC可以编译它,但有一个强烈的警告,并且生成的程序是错误的。
g++
会给出 error: lvalue required as left operand of assignment
。 - underscore_d&x
作为左值也是无效的。引用只是 x 的别名。改变一个地址有什么意义呢?地址就是一种存在的东西。它不可分配。或者最多,它是 x
地址的具体化临时副本,可以分配,但不会影响 x
的地址。 - v.oddou在TC++PL中,Bjarne Stroustrup说,引用可以被视为对现有实体(对象或函数)的另一个名称。虽然这并不总是实现引用的底层机制的最精确描述,但它是引用在语言级别上旨在实现的概念的非常好的描述。不出所料,语言没有提供任何手段来获取引用本身的地址。
在语言层面上,引用不能保证占据存储空间,并且因此在一般情况下它没有地址。
只需使用'&'运算符即可。 例如:
int x = 3;
int &y = x;
cout<<&y<<endl;
不能保证可靠性,因为引用不一定具有唯一的可寻址内存位置。
单独使用是不行的。如果您想要它的“地址”,请将其放入结构体或类中。即使这样,也不能保证能让您接近您可能想要使用指针的目的。如果您需要证明,请尝试使用char &并查看引用的大小。
这是可能的,但不严格使用C++。由于引用作为函数参数传递,其值将存储在堆栈或寄存器中。这取决于硬件架构。 访问这些值需要内联汇编。请查阅您正在使用的处理器的参考手册以确定堆栈行为和寄存器地址。破坏堆栈或寄存器可能会导致蓝屏、数据丢失甚至永久损坏您的系统。请极度小心操作。
struct TestRef{
int& r;
int i;
TestRef(int& ref): r(ref){
}
};
引用实际上是一个指针(在我的情况下使用Xcode编译器),您可以更新其值以将引用重新分配给新变量。为此,我们需要找到引用的地址,并将其值欺骗为其他变量的地址。
现在,引用TestRef.r的地址是TestRef对象的地址,因为r是TestRef的第一个成员。
您可以通过更新存储在TestRef.r内存中的值来重新分配引用。
以下代码显示了您可以获取引用的地址并将引用重新分配给不同变量。注意:我的操作系统是X64操作系统(我使用的是Xcode MacBook Pro 2015,MacOs 10.15.1)。
#include <iostream>
using namespace std;
struct TestRef{
int& r;
int i;
TestRef(int& ref): r(ref){}
};
int main(int argc, const char * argv[]) {
int i = 10;
int j = 11;
TestRef r(i); // r.r is reference to i
cout << r.r << " " << i << " " << j << endl; // Output: 10 10 11
int64_t* p = (int64_t*)&r; // int32_t in 32 bit OS;
// Note:
// p is the address of TestRef r and also the address of the reference r.r
// *p is the address of i variable
//
// Difficult to understand? r.r indeed a pointer to i variable
// *p will return the address inside the memory of r.r
// that is the address of i variable
// this statement is true: *p == &i
// ------>
// now we change the value of *p to the address of j
// then r.r will be the reference of j instead the reference of i
*p = (int64_t)&j; // int32_t in 32 bit OS;
cout << r.r << " " << i << " " << j << endl; // Output: 11 10 11
return 0;
}
实际上,你可以像黑客一样绕过重新分配引用的限制。
construct_at
可用于重新分配引用(在其位置上透明地创建一个新的引用,由现有名称访问),无需使用 hackish 技巧。C++20 提交了一个缺陷报告,称使用 placement-new 进行此操作实际上一直是合法的。 - Ben Voigt