寄存器和易失性有什么区别? 何时使用哪一个? 易失寄存器变量的含义是什么?
register int a;
volatile int a;
>volatile
表示变量的值可以通过编译器不可见的内容进行更改。这意味着变量必须具有有效的内存表示形式,必须在使用之前读取它,并在更改时存储。
register
- 如果可能,变量应存储在寄存器中。寄存器没有地址,因此不能在其上使用运算符&
。现在大多数编译器都忽略了,除了非常具体的形式:
AVR GCC 示例:register unsigned char counter asm("r3");
它将变量永久绑定到特定寄存器。它减少了寄存器池,使优化更加困难
注册无符号字符计数器 ASM("R3"(;
例子:
volatile int y;
int x8(volatile int x) // the x is read as many times as it is used
{
return x * x * x * x * x * x * x * x;
}
sub sp, sp, #8
str r0, [sp, #4]
ldr r3, [sp, #4]
ldr r1, [sp, #4]
ldr r2, [sp, #4]
mul r3, r1, r3
mul r3, r2, r3
ldr r2, [sp, #4]
ldr r0, [sp, #4]
mul r3, r2, r3
mul r3, r0, r3
ldr r2, [sp, #4]
ldr r0, [sp, #4]
mul r3, r2, r3
mul r3, r0, r3
ldr r0, [sp, #4]
mul r0, r3, r0
add sp, sp, #8
bx lr
int test(volatile int x) // parameter changed - stored
{
return x++;
}
sub sp, sp, #8
str r0, [sp, #4]
ldr r0, [sp, #4]
add r3, r0, #1
str r3, [sp, #4]
add sp, sp, #8
bx lr
int test2(void) same as above
{
return y++;
}
ldr r3, .L6
ldr r0, [r3]
add r2, r0, #1
str r2, [r3]
bx lr
当变量的修改可以是异步的(例如CPU中的寄存器(时,应始终使用volatile
关键字。
例如,您正在使用微控制器,并且在按下按钮时正在等待标志。然后你正在像这样阅读寄存器:
uint8_t* reg = 0x12345678; //Register address
while (*reg & 0x02) { //Read register until 0 = button pressed
}
这很容易失败,因为编译器会检查它一次,稍后会忽略值,你可能会以无限循环结束,或者你甚至没有得到任何东西,因为 CPU 可以缓存reg
的值,因为它假设没有人可以修改它指向的值。
如果这样做:
volatile uint8_t* reg = 0x12345678; //Register address
while (*reg & 0x02) { //Read register until 0 = button pressed
}
强制编译器在使用变量内容之前从实际内存中读取指令。在这种情况下没有缓存。
register
关键字只是编译器的提示,它应该将变量放入CPU寄存器,但情况并非总是如此,一些编译器会忽略此关键字。它是实现定义的。