【问题标题】:Address of a variable stored in a register存储在寄存器中的变量的地址
【发布时间】:2013-05-14 14:01:32
【问题描述】:

如果在我的代码中的某个地方,我使用了变量的地址(例如,将其传递给其他函数),编译器会自动选择将其存储在内存中吗? (与将其存储在寄存器中的可能性相反)。

否则,如果我要求这样的变量的地址(存储为寄存器)会发生什么?我知道我们不能将变量的地址显式设置为寄存器 (register int c)。

编辑

例如,如果我做类似的事情

int c = 1;
print("Address of c: %p", &c);

那么这个变量不能存储在寄存器中,是吗?编译器会自动将其设置为存储在内存中吗?否则(如果它只是存储在寄存器中),屏幕上显示的地址是什么?

【问题讨论】:

  • 我不清楚你在问什么。如果您在谈论函数参数,那么它们都是通过堆栈处理的。
  • 一些调用约定使用堆栈其他使用寄存器,或两者的组合。它们并非全部由堆栈处理,除非您使用特定编译器讨论特定架构上的特定调用约定。
  • 我的意思是在一般意义上使用变量的地址。例如,我可以将地址打印到屏幕上。
  • 同时添加“volatile”。

标签: c


【解决方案1】:

首先,C 标准禁止获取声明为register 的变量的地址,就像它对structs 中的位字段所做的那样。

对于非注册(“自动”)变量,简短的回答是肯定的。优化器最简单的策略是立即溢出地址被占用的变量。

“溢出”只是寄存器分配文献中的一个术语,意思是“决定放置在内存中而不是寄存器中”。

一个复杂的优化器可以进行一个别名分析并且仍然在一个寄存器中保存一个值,即使它的地址已经被占用了。只要可以证明生成的指针不可能用于更改值,这都是可能的。

另一个相关的优化是生存范围分割。这允许将变量存储在寄存器中,用于保存有用值的部分指令范围(其“有效范围”)并溢出到其他部分。在这种情况下,溢出的部分将对应于指针可能用于更改变量值的位置。例如:

x = 3;
... lots of computations involving x
if T {
  // SPILL HERE, so store register holding x to memory
  int *p = &x;
  ... lots of computations, perhaps using p to change x
  *p = 2;
  // DONE SPILL HERE, so reload register
  ... more code here not using p to change x.
}
else {
  ... lots of computations involving x.
}

此代码的积极优化器可能会为 x 分配一个堆栈位置,但将其加载到代码顶部的寄存器中,除了标记为 SPILL 的区域外,将其保留在那里。该区域将被寄存器存储到内存和匹配的寄存器加载所包围。

【讨论】:

  • 对不起,我没有真正理解第一段的第一句话。优化器(编译器)溢出那些变量?
  • “溢出”仅仅意味着寄存器分配器决定将变量放入内存而不是寄存器。发生溢出的原因有很多。也许最常见的是变量多于寄存器,因此一些变量必须“溢出”出可用的寄存器池。
【解决方案2】:

通过获取它的地址,您强制编译器将变量放入内存中,而不是将其优化到寄存器中。

这个答案有一些很好的信息:Address of register variable

【讨论】:

  • 这不准确。我使用cc -O3 -std=c99 -S 编译了int foo(int x) { int y = x, *z = &y; return *z * *z; } 和Apple clang 4.0 版,并检查了生成的汇编代码。它从未将xy 放入内存中。仅当编译器无法确定无法提供所需的“可观察”行为时,才会强制编译器将该值放入内存中。
【解决方案3】:

编译器在优化指针时必须非常小心,因为任何人都可以在后台更改它们。这就是为什么存在像restrict 这样的优化关键字的原因(告诉编译器在任何地方都没有指针的其他副本)。所以一般不会出现你描述的情况。

【讨论】:

    猜你喜欢
    • 2010-11-18
    • 2014-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-04
    • 2019-06-20
    • 2012-05-04
    • 2011-09-12
    相关资源
    最近更新 更多