代码之家  ›  专栏  ›  技术社区  ›  AlastairG

volatile关键字如何影响静态常量数组?

  •  1
  • AlastairG  · 技术社区  · 8 年前

    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};
    

    既然这是一个常数数组,为什么要使用 volatile 钥匙在这里?

    我的理解是 关键字表示数组的内容可以更改,但 const

    tmp = RCC->CFGR & CFGR_PPRE1_Set_Mask;
    tmp = tmp >> 8;
    presc = APBAHBPrescTable[tmp];
    

    当我转储 tmp presc 我发现 tmp公司 值为4和 PREC公司

    问题2:

    在声明期间,值会如何变化?

    这是可靠的。。。直到我移除 __一、 从数组声明中。这让我觉得这不是缓冲区溢出。除此之外,我想不出任何事情。

    不稳定的 关键字存在是有原因的,除了我在中断处理程序中也看到了如下代码,据我所知,其中 不稳定的

    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 宏替换为 :

    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关键字解决了这个问题!

    3 回复  |  直到 8 年前
        1
  •  7
  •   alain    8 年前

    我的理解是volatile关键字意味着内容 数组的属性可以更改,但常量意味着它们不能更改。

    volatile const 程序

    ,编译器假设可以读取一次值并多次使用。

        2
  •  1
  •   user5329483    8 年前

    这个 volatile const 实时时钟可以使用构造来发布当前时间:

    volatile const struct tm TheTimeNow;
    
    • const .
    • 时钟在您和编译器的后面永久而神奇地滴答作响,因此更好地使用 volatile

    RTC可能在地址空间中有自己的部分,其中显示当前时间。

        3
  •  0
  •   AlastairG    8 年前

    首先,感谢所有的评论和答案,让我找到了这个答案。

    如果定义变量时没有“volatile”关键字,则将其放入二进制文件的只读部分。

    我最近发现了3个缓冲区溢出,我确信还有其他缓冲区溢出。很多代码编写得不是很好。当指定“volatile”关键字时,变量很可能被放置在内存中,从而容易发生缓冲区溢出。没有任何理由将这个特定变量标记为volatile,因此简单的修复方法是删除该关键字。正确的解决方法是这样做,同时跟踪缓冲区溢出并进行修复。