是否可以将整个数组保存在CPU寄存器中

问题描述 投票:0回答:5

在下面的代码中,

int main( )
{
    register int arr[4];
    /* ... */
}

是否有可能“arr”被分配在某个CPU寄存器中。 (考虑CPU有4个或更多寄存器)。

否则编译器会忽略注册数组的存储类。

c embedded microcontroller microprocessors
5个回答
11
投票

根据我的理解,答案是

因为,

  1. 任何数组元素都必须是显式可寻址的(即,对于 16 位 uC/uP,其地址应始终位于 0x0000 到 0xFFFF 地址空间之间。)

  2. CPU寄存器使用寄存器直接寻址模式访问(如mov r2,#100)。 这种寻址方式没有有效地址。 ( 即使它不被认为是一种寻址模式 )

  3. 数组元素必须驻留在连续的内存位置。 (对于指针运算,使用数组的主要原因)

因为,

  1. 编译器可以为上面的数组分配寄存器,以便我们可以对其进行一些有限的操作。 但不能使用内部使用地址进行优化的操作。

请参阅下面的代码。

int main( )
{
  register int arr[4];
  int i;

  arr[0] = 10;      /* OK */
  arr[1] = 20;      /* OK */
  arr[2] = 30;      /* OK */
  arr[3] = 40;      /* OK */

  for(i=0;i<4;i++)
    arr[i]=10;    /* Error : "address of register variable 'arr' requested" */

  return 0;
}

所以我的最终结论是,理想情况下,register存储类永远不应该与array一起使用,即使你的编译器允许。

请纠正我或提供更多意见。 :-)


10
投票

请勿将

register
作为关键字与 CPU 寄存器混合使用。你的代码

register int arr[4];

使得

arr
完全无法访问,因为您无法获取对象的地址。基本上你唯一能用它做的就是
sizeof arr


6
投票

我写了这段代码:

int foo(int x, int y)
{
    register int a[2] = {x, y};
    return a[0] + a[1];
}

并使用 Apple clang 4.0 版本使用

cc -O3 -std=c99 -S
进行编译,并生成此程序集(省略了各种调试和不相关的修饰):

_foo:
    pushq   %rbp
    movq    %rsp, %rbp
    addl    %esi, %edi
    movl    %edi, %eax
    popq    %rbp
    ret

所以,从某种意义上说,数组保存在寄存器中。然而,这更多的是优化的产物,事实上对数组的所有引用都是通过常量索引而不是由于

register
关键字。所以答案是“嗯,从理论上讲,这是可能发生的。但它几乎没有实际用处,你通常不能依赖它。”

某些处理器具有可索引寄存器,例如 ARM 处理器上的 NEON 寄存器,其中包含可以在某些指令中独立寻址(通过立即值)的多个值。我可以设想一个编译器在 NEON 寄存器中保存一小部分值并独立访问它们,前提是源代码引用可以在编译时解析为常量。


6
投票

C89标准不允许对寄存器存储类的变量进行地址或任何类似的操作(至少我的草案不允许:3.5.1,参考注释49)。它甚至提到只有 sizeof 运算符对于这样的数组有效。 C99标准引用了6.7.1中的寄存器存储类,其中注释103声明与C89草案完全相同。

所以总而言之,寄存器存储类和数组确实不应该混合。声明本身是有效的,但从技术上讲是没有用的。

否则一般当您有疑问时,请检查反汇编列表。一些针对 8 位控制器的编译器可能会做一些令人惊讶的事情。


1
投票

优化编译器可能会临时将它认为适合的任何数组元素分配给 CPU 寄存器,并且只在那里执行操作。

但是如果您询问是否可以强制该数组进行寄存器,那么我不知道如何做到这一点。对于单个变量(在 gcc 中),您可以使用“显式寄存器变量”(请参阅 http://gcc.gnu.org/onlinedocs/gcc/Explicit-Reg-Vars.html)。

© www.soinside.com 2019 - 2024. All rights reserved.