在下面的代码中,
int main( )
{
register int arr[4];
/* ... */
}
是否有可能“arr”被分配在某个CPU寄存器中。 (考虑CPU有4个或更多寄存器)。
否则编译器会忽略注册数组的存储类。
根据我的理解,答案是是和否。
不因为,
任何数组元素都必须是显式可寻址的(即,对于 16 位 uC/uP,其地址应始终位于 0x0000 到 0xFFFF 地址空间之间。)
CPU寄存器使用寄存器直接寻址模式访问(如mov r2,#100)。 这种寻址方式没有有效地址。 ( 即使它不被认为是一种寻址模式 )
数组元素必须驻留在连续的内存位置。 (对于指针运算,使用数组的主要原因)
和是因为,
请参阅下面的代码。
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一起使用,即使你的编译器允许。
请纠正我或提供更多意见。 :-)
请勿将
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];
}
并使用 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 寄存器中保存一小部分值并独立访问它们,前提是源代码引用可以在编译时解析为常量。
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)。