我不是编译器专家,但我的印象是它有点相反。首先,编译器尝试优化代码。如果优化后不需要变量的地址,则将其放入寄存器中(或者可能优化完全不存在)。
当然,如果&运算符根本没有应用于变量,那么它肯定是一个候选者。但是即使&x源代码中确实出现了,优化后对地址的需要也可能消失。
作为一个简单的例子,如果我们有
int x = 7;
foo(*&x);
编译器可以看到它*&x与 完全等价x,因此可以将代码视为只是foo(x)。如果 的地址x没有被其他任何地方占用,那么它就不再需要有地址,并且可以进入寄存器。
现在您可以想象将这种分析扩展到更复杂的代码。
int x = foo1(), y = foo2();
int *p;
p = cond ? &x : &y;
return *p;
在godbolt上试试
从概念上讲,这可以连续重写为
return *(cond ? &x : &y);
return cond ? *&x : *&y;
return cond ? x : y;
现在x,y不再需要有地址,p也不再需要存在。
所以换句话说,编译器不会试图“模拟”&操作符;相反,它会尝试重构代码以使其不再需要。
这不可能的最常见情况是变量的地址被传递给另一个函数。
int x;
foo(&x);
除非foo可以内联或其他类型的过程间分析可用,否则编译器确实必须将某些东西的地址传递给foo,因此x必须存在于内存中,至少在那一刻是这样。当然,编译器可以选择在之后立即将其移动到寄存器中,如果不再需要它的地址,则将其保留在函数的其余部分中;变量是存在于内存中还是存在于寄存器中的问题不需要一直固定。