【问题标题】:Global register variables in gccgcc 中的全局寄存器变量
【发布时间】:2015-02-06 07:08:17
【问题描述】:

最近在面试中被问到全局寄存器变量。我搞砸了,说任何全局变量都将存储在Data段中。但是后来我被问到GCC。面试后我得出结论,gcc支持全局寄存器变量.

#include<stdio.h>

register int var asm("ebx");  //storing global variable in register explicitly

int main(void)
{
.......
}

这里是链接 https://gcc.gnu.org/onlinedocs/gcc/Global-Reg-Vars.html#Global-Reg-Vars

但现在我对它的生命周期和范围感到困惑,以及它是作为普通的全局变量还是作为寄存器变量工作?还有什么方法或一些 gcc 上的命令 以便我们确保编译器不会简单地忽略 register 关键字并将存储在实际寄存器中?

【问题讨论】:

  • 你不能通过调试器试试吗?
  • @MrSykkox:你能帮我解决这个问题吗?你也可以回答我的第一个问题吗?我会很感激的。
  • 我不确定寿命,但要测试一下。如果您使用的是 gdb ( -ggdb ),则使用调试标志 ( -g ) 进行编译。在您的主要代码集中 var = something.退出前设置断点。并打印寄存器值( info register ebx )。
  • 另外,请注意C++11 has deprecated register。 C 并没有盲目地追随 C++,但写作已成定局。不要在 C 中使用auto;不要在新的 C 代码中使用 register (你可以在旧的 C 代码中安全地删除它)。将register 用于全局变量会将您绑定到特定的C 编译器,并且基本上没有任何好处。请记住,register 是对编译器的提示,而不是命令;编译器可以根据您的提示进行操作。使用register 确实会阻止您获取变量的地址,但仅此而已。
  • 如果你的面试官想用关于奇怪的 gcc 扩展的问题来欺骗你,那么你可能不想和这些人一起工作!

标签: c gcc


【解决方案1】:

正如许多人所指出的,在全局范围内保留寄存器通常不是一个好主意。我相信这里的初衷是(来自docs):

这在编程语言等程序中可能很有用 具有几个可访问的全局变量的解释器 经常。

这是否真的有用,或者最终只会让事情变得更糟,可能只能针对特定情况来确定。在你的情况下(面试问题),这并不重要。

像这样的声明的范围是看到声明的所有内容,就像您对任何全局声明所期望的一样。

但是,实现有点棘手。再次引用文档:

在某个寄存器保留区中定义一个全局寄存器变量 完全注册用于此用途,至少在当前 编译。该寄存器不分配用于任何其他目的 当前编译中的函数,不保存 由这些函数恢复。

因此,使用该声明编译的所有代码都将保留该寄存器供该用途使用。但是,如果您链​​接到未使用此保留编译的其他代码,则不会为此目的保留它。

文档给出了一个很好的 qsort 示例。如果您的代码是使用此声明编译的,然后它从 c 运行时调用 qsort(可能未使用此声明编译),然后 qsort 回调到您的代码中(对于比较函数),回调不能确保 qsort 在调用比较函数之前不会踩到寄存器。

如果调用任何库函数都可以踩到寄存器,这怎么可能?再次来自文档:

选择一个通常由函数保存和恢复的寄存器 在你的机器上调用,这样库例程就不会破坏它。

即便如此:

从信号访问全局寄存器变量是不安全的 处理程序,或来自多个控制线程,因为系统 库例程可能会暂时将寄存器用于其他事情 (除非您专门为手头的任务重新编译它们)。

至于你问题的最后一部分:

编译器不会简单地忽略 register 关键字,而是存储在 实际寄存器

我不确定你的意思。如果(不知何故)编译器忽略了asm("ebx"),那么它将不会存储在寄存器中。使用它的全部目的是确保var 存储在实际的 ebx 寄存器中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-08-06
    • 2020-02-07
    • 1970-01-01
    • 2015-03-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多