这是一个引人注目的人,任何能够回答的人都应该得到大家的认可!这实际上是一些我想要获得更好理解的相关问题。volatile关键字如何影响静态常量数组?
为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};
__I
被定义为:
#ifdef __cplusplus
#define __I volatile /*!< defines 'read only' permissions */
#else
#define __I volatile const /*!< defines 'read only' permissions */
#endif
我的程序是用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};
问题1:
考虑到这是一个常量数组,为什么在这里使用volatile
keywork?
我的理解是,volatile
关键字表示数组的内容可以改变,但const
意味着他们不能。
唯一使用此阵列中的代码的是三种用途这样的:
tmp = RCC->CFGR & CFGR_PPRE1_Set_Mask;
tmp = tmp >> 8;
presc = APBAHBPrescTable[tmp];
当我转储tmp
和presc
值我发现tmp
具有4和presc
的值具有值0.索引4是数组的第5个元素,其值为1.没有其他访问或使用此值......总之......任何地方。
问题2:
怎么可能值它被宣布之间改变了吗?
当我转储数组时,我看到它充满了零。
它可靠地发生......直到我从数组声明中删除__I
。这使我认为它不是缓冲区溢出。除此之外,我无法想到任何事情。
我倒觉得volatile
关键字是有原因的,但我也看到像在中断处理程序下面的地方,据我了解,在volatile
关键字是多余的代码:
volatile uint32_t status = USART2->SR;
这个变量对函数来说是局部的,因此其他地方的代码永远不会改变它。
========额外的细节========
下面是相关的代码的注释的反汇编。在(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]
这里是相同的,但与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]
它们本质上是相同的。然而,以某种方式删除volatile关键字可以解决问题!
可能值得注意的是,有问题的代码由Keil交叉编译器人员提供,并被观察到可以在该板上正常工作多年 - 但使用Keil编译器而不是GCC编译器。 – AlastairG
有很多程序使用'volatile'作为魔法护身符,而不理解它的实际功能。我怀疑这是其中的一个程序。 – zwol
'__I' = UB。你应该重命名这个符号。 – Bathsheba