在下面的代码中,
int main( )
{
register int arr[4];
/* ... */
}
是否有可能在某个 cpu 寄存器中分配了“arr”。(考虑 cpu 有 4 个或更多寄存器)。
否则编译器将忽略数组的寄存器存储类。
在下面的代码中,
int main( )
{
register int arr[4];
/* ... */
}
是否有可能在某个 cpu 寄存器中分配了“arr”。(考虑 cpu 有 4 个或更多寄存器)。
否则编译器将忽略数组的寄存器存储类。
据我了解,答案是YES和NO。
不,因为,
任何数组元素都必须是显式可寻址的(例如,对于 16 位 uC/uP,其地址应始终位于 0x0000 到 0xFFFF 地址空间之间。)
使用寄存器直接寻址模式(例如mov r2,#100)访问 CPU 寄存器。这种寻址方式没有有效地址。(即使它不被认为是一种寻址模式)
数组元素必须驻留在连续的内存位置。(对于指针运算,使用数组的主要原因)
是的,因为,
请参见下面的代码。
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
关键字与 CPU 寄存器混合使用。你的代码
register int arr[4];
使其arr
完全无法访问,因为您无法获取对象的地址。基本上你唯一能用它做的就是sizeof arr
.
我写了这段代码:
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 寄存器中保存一个小的值数组并独立访问它们,前提是源代码引用可以在编译时解析为常量。
C89 标准不允许对寄存器存储类的变量进行地址或任何类似操作(至少我的草案没有:3.5.1,参考注释 49)。它甚至提到只有 sizeof 运算符对这样的数组有效。C99 标准引用了 6.7.1 中的寄存器存储类,其中注释 103 声明与 C89 草案完全相同。
所以总而言之,寄存器存储类和数组真的不应该混用。声明本身是有效的,但从技术上讲它是无用的。
否则,通常当您有疑问时,请查看反汇编列表。一些针对 8 位控制器的编译器可能会做一些令人惊讶的事情。
优化编译器可能会临时将它认为适合的任何这些数组元素分配给 CPU 寄存器,并且只会在那里进行操作。
但是如果你问是否可以强制该数组注册,那么我不知道如何做到这一点。对于单个变量(在 gcc 中),您可以使用“显式寄存器变量”(参见http://gcc.gnu.org/onlinedocs/gcc/Explicit-Reg-Vars.html)。