这是一个思想家,任何能够回答它的人都值得大家认可!这实际上是我要求更好理解的几个相关问题.
STM32 ARM Cortex平台的驱动程序包含以下代码:
static __I uint8_t APBAHBPrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9};
Run Code Online (Sandbox Code Playgroud)
__I 定义为:
#ifdef __cplusplus
#define __I volatile /*!< defines 'read only' permissions */
#else
#define __I volatile const /*!< defines 'read only' permissions */
#endif
Run Code Online (Sandbox Code Playgroud)
我的程序是一个用GCC交叉编译器编译的C程序.因此数组声明是有效的:
static volatile const uint8_t APBAHBPrescTable[16] = {0, 0, 0, 0, 1, 2, 3, 4, 1, 2, 3, 4, 6, 7, 8, 9};
Run Code Online (Sandbox Code Playgroud)
问题1:
鉴于这是一个常数数组,为什么要在volatile这里使用关键字?
我的理解是volatile关键字意味着数组的内容可以改变,但const意味着它们不能改变.
在代码中唯一使用此数组是这样的三个用法:
tmp = RCC->CFGR & CFGR_PPRE1_Set_Mask;
tmp = tmp >> 8;
presc = APBAHBPrescTable[tmp];
Run Code Online (Sandbox Code Playgroud)
当我转储的值tmp和presc我发现tmp具有为4的值,并且presc具有0指数4的值是具有1有没有其他访问或该值的用途的值数组的第5个元素.. .所有......任何地方.
问题2:
如何宣布它之间的价值变化?
当我转储数组时,我看到它充满了零.
它可靠地发生......直到我__I从数组声明中删除它.这让我觉得它不是缓冲区溢出.除此之外,我什么都想不到.
我认为volatile关键字是有原因的,除了我在中断处理程序中看到如下代码,据我所知,volatile关键字是多余的:
volatile uint32_t status = USART2->SR;
Run Code Online (Sandbox Code Playgroud)
此变量是函数的本地变量,因此其他地方的代码永远不会更改.
========额外细节========
以下是相关代码段的带注释的反汇编.(RCC_GetClocksFreq + 128)处的值为零,但在某些时候出现以将预分频器查找表的地址复制到其中:
0x000001d0 <+56>: ldr r1, [pc, #68] ; (0x218 <RCC_GetClocksFreq+128>)
...
tmp = RCC->CFGR & CFGR_PPRE1_Set_Mask;
tmp = tmp >> 8;
0x000001de <+70>: ldr r4, [r2, #4]
0x000001e0 <+72>: ubfx r4, r4, #8, #3
presc = APBAHBPrescTable[tmp];
0x000001e4 <+76>: ldrb r4, [r1, r4]
RCC_Clocks->PCLK1_Frequency = RCC_Clocks->HCLK_Frequency >> presc;
0x000001e6 <+78>: lsr.w r4, r3, r4
0x000001ea <+82>: str r4, [r0, #8]
Run Code Online (Sandbox Code Playgroud)
这是相同的,但volatile const宏替换为const:
0x000001d0 <+56>: ldr r4, [pc, #68] ; (0x218 <RCC_GetClocksFreq+128>)
...
tmp = RCC->CFGR & CFGR_PPRE1_Set_Mask;
tmp = tmp >> 8;
0x000001de <+70>: ldr r1, [r2, #4]
0x000001e0 <+72>: ubfx r1, r1, #8, #3
presc = APBAHBPrescTable[tmp];
0x000001e4 <+76>: ldrb r1, [r4, r1]
RCC_Clocks->PCLK1_Frequency = RCC_Clocks->HCLK_Frequency >> presc;
0x000001e6 <+78>: lsr.w r1, r3, r1
0x000001ea <+82>: str r1, [r0, #8]
Run Code Online (Sandbox Code Playgroud)
它们基本相同.然而,以某种方式删除volatile关键字解决了这个问题!
我的理解是volatile关键字意味着数组的内容可以改变,但const意味着它们不能改变.
volatile表示程序必须在每次使用时从内存中读取值.const表示程序可能不会更改值,但环境(或"OS")可能会更改.
这解释了您观察到的行为:如果没有volatile,编译器会认为可以读取一次值并多次使用它.