如何在C中选择寄存器变量?

时间:2015-07-10 07:18:07

标签: c gcc optimization cpu-registers

请注意:我原本打算将此问题标题为“何时在C中使用寄存器?”,但它似乎是某人already beat me to the punch然而,与标题相比,问题的提问方式有点误导,我相信这个问题是独一无二的,并且不是它的愚蠢。

然而,这个问题确实应该标题为“ register变量真的更快吗?”,我实际上想知道何时应该使用 registers。对我来说很明显,它们实际上速度更快,但显然你的CPU只有很多芯片注册,所以你受限于它们可以存储在它们上面。

所以我问:如何选择哪些变量应该被register限定?与特定频率一起使用的变量?特定大小或类型的变量?在计算限制问题中使用的变量?还有别的吗?

我这样看:对于每个产品所有者或利益相关者,每个单个错误或功能都是“最优先”和关键。但是,如果你真的分析他们的需求,你会发现某些功能比其他功能更“优先”。使用代码,您希望它尽可能快地运行,因此我确信每个变量都是优化/性能调优的候选者。但我想想象如果你真的分析一个程序(或者C编译器就这个问题,让我们假设gcc),我确信有一种方法可以确定哪个变量最适合与register一起使用。

4 个答案:

答案 0 :(得分:6)

首先,让我告诉您,不要被register源代码中C的出现所迷惑。

您的编译器完全可以忽略它(大部分时间都是如此)。在现代编译器中,使用register很可能是无用的。

通常,任何"标准"编译器将有自己的算法来检测并放入适当的变量以将它们分配给寄存器(或不是)。大多数时候,它们都非常正确。留给他们。

FWIW,只有一件事需要记住,无法获取register变量的地址。这是使用register的唯一原因(如果我们可以将其视为"原因")。也许

答案 1 :(得分:0)

有些时候register很有用......当与扩展程序集一起使用时。

#define STACK_POINTER "esp"
char **environ;
_start(void){
  register long *sp __asm__( STACK_POINTER );
  long argc = *sp;
  char **argv = (char **)(sp + 1);
  environ = (char **)(sp + argc + 1);
  exit(main(argc, argv, environ) );
  __builtin_unreachable(); //or for(;;); to shut up compiler about returning
}

在Linux(可能是其他版本)中,即使架构将一些参数作为寄存器传递,elf二进制文件也会在堆栈上传递_start args。由于没有标准化的方法来访问堆栈指针,您必须在所有程序集中编写start或使用这样的扩展来通过变量访问特定的命名寄存器。您也可以指定一个值

register long *syscall_num __asm__( "eax" ) = __NR_open;
...

这对于函数通常在栈上传递参数的相反情况很有用,但是特殊函数(syscall等...)需要在某些寄存器中传递参数。

如果编译器支持该语法,则这两种机制将使用寄存器,但不是,使用register int i;或类似物没有保证。

答案 2 :(得分:0)

register关键字在定义调用ABI的扩展时非常有用,例如创建可以传递多个参数的函数;或者为本地内存管理器等全局分配寄存器。

register int g_imag __asm__ ("r14");

int complex_multiply(int real, int imag, int r2, int i2)
{
    g_imag = real*i2 + imag*r2;    // put to "global" variable
    return real*r2 - imag*i2;
}

仅使用被调用者保存的寄存器来保证将r14用于其他目的的函数首先将内容溢出到堆栈。缺点是减少了其他功能中的可用寄存器,以及其他人已经指出,只有在工作时才能工作。

答案 3 :(得分:-1)

如您所知,寄存器是CPU使用的快速存取存储器。它们主要受存储空间的限制,有些是8位,有些是256位。 我记得它比DRAM快10倍左右,比如5到50 ns(不确定)。

使用它取决于您正在处理的字段。 例如,使用嵌入式电子设备时,使用寄存器很有用,当您经常使用全局const时,将其设置为寄存器将使您的程序成为"更快"

但请记住,这是一个优化问题,除非您正在使用要求很高的算法或嵌入式电子产品,否则无需深入研究。如上所述,编译器可以检测经常使用的变量并尝试将它们自动存储在寄存器中。

但是如果你真的想要使用它,请记住你应该设置经常使用的变量或常量并且不大于寄存器大小!