反汇编中的引用类型和指针
Posted
技术标签:
【中文标题】反汇编中的引用类型和指针【英文标题】:Reference type and pointer in disassembly 【发布时间】:2010-12-02 20:20:47 【问题描述】:为什么编译代码中的引用类型和指针是相同的?(你可以在第三和第四行看到)。我试图弄清楚,但显然我无法实现。
如果引用类型变量必须在声明时初始化并且不能更改,那么是否需要像在指针中那样进行间接寻址?
int x = 10;
mov dword ptr [x],0Ah
int y = x;
mov eax,dword ptr [x]
mov dword ptr [y],eax
int &i = y;
lea eax,[y]
mov dword ptr [i],eax
int *p = &x;
lea eax,[x]
mov dword ptr [p],eax
p = &i;
mov eax,dword ptr [i]
mov dword ptr [p],eax
x = i;
mov eax,dword ptr [i]
mov ecx,dword ptr [eax]
mov dword ptr [x],ecx
【问题讨论】:
【参考方案1】:如果编译器知道引用总是引用单个特定对象/项,那么编译器当然可以优化掉间接。
然而,大多数引用实际上是在运行时绑定的。即使无法重新绑定引用的特定实例,特定范围的不同执行或包含引用成员的对象的不同实例也可能会在引用绑定到每个实例的不同对象的情况下运行。使用间接是编译器处理这个问题的一种方便的方法。
引用仅绑定到单个事物的情况可能相对较少,以至于编译器可能不会寻找优化 - 特别是因为在大多数情况下优化可能不会带来明显的收益。
另外,我怀疑您没有打开编译器优化 - 使用您的代码并使用 y
和 i
及其地址调用各种函数,在 VC++ 2005 中进行了优化的快速测试表明编译器没有将i
实现为指针,但作为y
的真正别名(即,无论何时传递i
或&i
,编译器都会直接使用y
的地址)。
如果您正在查看编译器的调试输出,您应该不会感到惊讶,它始终将引用视为幕后的指针。
【讨论】:
抱歉,有没有“然而,大多数引用实际上是在运行时绑定”的例子? @ilker: - 示例可能是一个引用,它是由构造函数参数设置的类的实例成员或函数本地的引用。【参考方案2】:引用只不过是受限制的指针。唯一的区别是它们必须指向一个现有的变量。你可以在 C++ 中解决这个问题,但它更难被忽略:
int& r = *(reinterpret_cast<int*>(0x0));
当然这是未定义的行为!
所以,基本上它们实现为指针。它们在许多地方的用法不同,例如。引用作为右值或左值出现时会自动取消引用:
int x = 0;
int& r = x; // 1) no need to take the address of x like &x
r = r * x; // Manually: (*r) = (*r) * x
它们为原始指针提供了一种更安全的替代方案。此外,它们具有比原始指针更优雅的语法。试想一下,重载类运算符时没有引用。
总而言之,它们是受限指针,具有更好/更安全的别名,但功能有所减少。
【讨论】:
引用不一定有助于别名 - 您的示例显示r
和 x
别名相同的对象。由于该别名,表达式 (r++ * ++x)
将具有未定义的行为。
"引用只不过是受限制的指针。"这不符合标准,这是一个实现细节。按照标准,它是对象的别名,所以它是对象,而不是指向它的指针。我知道你已经澄清了,但我想指出第一句在技术上是不正确的。
@Michael 很棒的观察。在 C++ 中,未指定参数评估的顺序。因此,在这种情况下,引用并不特殊。对吗?
@John 我知道,你说的是真的,但它们与指针共享相同的功能,别名。有什么引用可以做,指针不能做吗?我们不能将引用功能视为指针功能的子集吗?
从技术上讲,按照标准,它们并不相同。指针指向包含对象的内存地址,引用是对象的别名(另一个名称)。由此产生了几个很大的不同: 1. 您不能重新设置引用,但可以使用指针。 2. 指针是一个整数(大小取决于架构),您可以将其转换为整数。您不能使用引用(当然,除非它是对整数形式的引用,但它会转换值,而不是地址)。 3. 指针可以为NULL,引用不能。这些差别很大。【参考方案3】:
引用在内部表示为指针。是编译器对初始化和不可重置性施加了限制。
如果引用类型变量必须是 在声明时初始化并且不能 被改变所以有什么需要做的 指针中的间接寻址?
唯一的选择是复制值,这不是引用的作用。引用的作用类似于指针:它保存对象的位置。不同之处在于引用的行为类似于对象本身,而不需要显式取消引用。
【讨论】:
不能只是一个别名?假设“i”和“y”可以具有相同的值[在上面的示例中]。 @rlbond 实际上,C++ 标准需要这种行为(8.3.2:应初始化引用以引用有效的对象或函数。)所以编译器应该需要它。 :)【参考方案4】:C++ FAQ lite 很好地解释了您所看到的内容:https://isocpp.org/wiki/faq/references
本质上,简而言之,编译器本质上将其视为指针,它使用对象的地址并为您完成解引用工作。
【讨论】:
【参考方案5】:是的,引用只是指针的语法糖(具有适用于新语法的限制)。它还让 C++ 看起来具有按引用复制的参数传递,而 C 仅具有按值复制(甚至是指针参数)
【讨论】:
以上是关于反汇编中的引用类型和指针的主要内容,如果未能解决你的问题,请参考以下文章