【问题标题】:Is there any way to find the address of a reference?有没有办法找到引用的地址?
【发布时间】:2010-12-29 09:03:01
【问题描述】:

有没有办法找到引用的地址?

更具体:变量本身的地址,而不是初始化变量的地址。

【问题讨论】:

  • @Sandeep:“变量本身”只是初始化它的变量的另一个名称。在指针的情况下没有单独的变量。引用和被引用的变量都是同一个变量。
  • 这个案例只是引用毫无用处的另一个原因。它们基本上只适用于无法输入 -> 而想输入 . 的人。
  • @Cosine:什么?!完全垃圾。
  • @MooingDuck:我仍然认为这是一个抽象泄漏:P
  • 我希望这样的 Qs 必须给出一个理由,为什么 OP 可能想要所要求的理论上的东西。至于那些列出引用的人,他们只是背叛了他们在 C++ 方面的经验是如此有限,他们从未编写过任何引用是强制性的或至少有帮助的代码 - 而且这在某种程度上是对语言的控诉(!)他们是习惯于隐式传递引用的语言并且没有看到抱怨 C++ 提供相同能力的讽刺意味?他们是否认为“通过引用”应该全部由指针手动完成,导致 C 代码混乱?我想我们永远不会知道!

标签: c++ reference


【解决方案1】:

只需使用“&”运算符。 例如:

int x = 3;
int &y = x;
cout<<&y<<endl;

这将返回 x 的地址,因为 y 只不过是 x 的地址。

【讨论】:

  • 我认为 Sandeep 的意思是引用本身的地址
  • 这将有效地打印出 x 的地址(因为 y 作为引用只是 x 的另一个名称)。
  • 是的,我实际上不确定他/她是指引用指向的地址还是引用本身,所以我发布了这个答案以防万一。但是,引用不就是它所指向的地址吗?那么在我的示例中,引用的地址将是“x”的地址?我是在想。 :)
  • 哦,引用只是对象的别名(替代名称)。它没有自己的记忆单元。
  • @Sandeep:“指针有自己的地址”。正确的。那是因为指针是一个单独的变量,它保存着它所指向的变量的地址。在引用的情况下,没有单独的变量。引用只是被引用变量的另一个名称。获取引用的地址只会返回被引用变量的地址。
【解决方案2】:

不可靠,因为引用不必在可寻址内存中具有唯一的位置。

【讨论】:

    【解决方案3】:

    引用没有自己的地址。尽管引用可以实现为指针,但没有必要或保证这一点。

    The C++ FAQ 说得最好:

    与指针不同,一旦引用 绑定到一个对象,它不能 “重新安置”到另一个对象。这 引用本身不是一个对象(它 没有身份;取地址 一个参考给你的地址 所指;记住:参考 是它的参照物)。

    也请在此处查看我的答案以获取 comprehensive list of how references differ from pointers

    引用就是它的所指对象

    【讨论】:

    • 你是对的。但有时使用术语别名比使用术语更容易。
    • 是否有任何将引用作为指针的示例实现?我真的很想看看他们是如何实现的。如果你遇到任何例子,请分享。
    • @Saran:GCC 是开源的。
    • 顺便说一句,这条规则击败了va_start(vargs,a_referece_argument)。 :(
    • @Mordachai:不是真的,不是; va_start 带有引用类型的第二个参数是 UB。
    【解决方案4】:

    没有。

    正如 Bjarne Stroustrup 在 TC++PL 中所说,可以将引用视为现有实体(对象或函数)的另一个名称。虽然这并不总是对实现引用的底层低级机制的最精确描述,但它很好地描述了引用旨在在语言级别实现的概念。毫不奇怪,该语言没有提供获取引用地址本身的方法。

    在语言级别,不能保证引用在存储中占据一席之地,因此在一般情况下它没有地址。

    【讨论】:

      【解决方案5】:

      ISO 标准说得最好:

      不得有对引用的引用,不得有引用数组,也不得有指向引用的指针。

      我不喜欢很多人在这里使用的逻辑,你不能这样做,因为引用不是“保证只是某个地方的指针”。就像int x 可能只是一个没有地址的处理器寄存器,但在使用&amp; 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 这总是邪恶的,与参考精神背道而驰。我不知道它是否曾经是一个预期的功能,或者只是编译器中的一个泄漏抽象,它忘记阻止左值访问内部指针。
      【解决方案6】:

      不是单独的。如果您想要它的“地址”,请将其放入结构或类中。即使那样,也不一定能保证让您接近您可能想要做的事情,即使用指针。如果要证明,引用的 sizeof 等于引用的类型。用 char & 试试看。

      【讨论】:

        【解决方案7】:

        。无法获取引用的地址。
        那是因为引用不是一个对象,它是一个别名(这意味着它是一个对象的另一个名称)。

        int  x = 5;
        int& y = x;
        
        std::cout << &x << " : " << &y << "\n";
        

        这将打印出相同的地址。
        这是因为“y”只是对象“x”的另一个名称(别名)。

        【讨论】:

        • 但可以说是它的地址。
        • @PaulChilds 是的。但不是以OP所询问的方式。查看问题。
        【解决方案8】:

        来自同一问题的另一个实例:$8.3.2/3 -“未指定引用是否需要存储 (3.7)。”。

        因此,C++ 标准允许编译器/运行时实现者选择引用是否位于单独的内存位置。但是请注意,如果它确实存在于单独的内存位置,则无法以符合标准的方式找到它的地址。所以不要这样做。

        如果您获取引用的地址,根据 C++ 标准中的定义,您将获得它所引用的地址,而不是引用的地址,如果事实上该引用甚至作为单独的实体存在于运行时环境与否。

        【讨论】:

          【解决方案9】:

          这是可能的,但不严格使用 C++。由于引用是作为函数的参数传递的,因此它的值将存储在堆栈或寄存器中。 这取决于硬件架构。 访问这些值需要内联汇编。请查阅您使用的处理器的参考手册以确定堆栈行为和寄存器地址。 损坏堆栈或寄存器很容易导致 BSOD、数据丢失,甚至对您的系统造成永久性损坏。 请格外小心。

          【讨论】:

            【解决方案10】:

            如果将引用实现为结构的成员,则可以获取其地址:

            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;
            }
            

            所以实际上你可以像黑客一样重新分配参考。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多