10

在下面的代码中,

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

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

否则编译器将忽略数组的寄存器存储类。

4

5 回答 5

11

据我了解,答案是YESNO

,因为,

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

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

  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;
}

所以我的最终结论是,即使您的编译器允许,理想情况下,寄存器存储类也不应该与数组一起使用。

请纠正我或提供更多输入。:-)

于 2013-06-27T12:14:47.417 回答
9

不要将register关键字与 CPU 寄存器混合使用。你的代码

register int arr[4];

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

于 2013-06-27T12:33:30.443 回答
6

我写了这段代码:

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

cc -O3 -std=c99 -S用 Apple clang 4.0 版本编译它,它产生了这个程序集(省略了各种调试和不相关的装饰):

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

因此,从某种意义上说,数组保存在寄存器中。然而,这更像是优化的产物,并且所有对数组的引用都是通过常量索引而不是由于register关键字。所以答案是“嗯,理论上,它可能会发生。但它几乎没有实际用处,你通常不能依赖它。”</p>

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

于 2013-06-27T14:05:59.647 回答
5

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

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

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

于 2013-07-02T17:29:26.967 回答
1

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

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

于 2013-06-27T13:45:08.103 回答