铸造挥发性表达式的结果为void(Casting the results of a volatile

2019-10-20 03:40发布

注意:

这是不是已经问了很多次同样的事情。 是的,我已经阅读了很多很多的职位有关转换为void。 这些问题没有引起我怀疑是这里真正的答案。


背景信息:

嵌入式C.这具体涉及存储器映射的挥发性指针。 换句话说,外设寄存器。

我遇到了在涉及写入一个I2C外围例行下面一行:

(void) I2C1->SR2;

I2C1已经#defined为结构*易失性存储器。

所以此行的结果不是“避免编译器警告”因为是我在这里做了所有的搜索答案。 事实上,这是导致编译器来读取寄存器(因为它是挥发性的),然后把它扔掉。 该寄存器具有标志在里面。 读寄存器的行为造成的标志清除。

现在,这是非常重要的,因为目标是明确的标志不只是避免了一些编译器警告!

有什么我却担心,就是在优化或者一个不同的编译器的某些层面,这段代码将得到优化。 这是我的问题:

这是否会得到优化,还是有办法保证它不会被优化掉?

我把所有的相关的代码下面一起:

#define PERIPH_BASE           ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region                                */
#define APB1PERIPH_BASE       PERIPH_BASE
#define I2C1_BASE             (APB1PERIPH_BASE + 0x5400)
#define I2C1                ((I2C_TypeDef *) I2C1_BASE)
typedef struct
{
  __IO uint16_t CR1;        /*!< I2C Control register 1,     Address offset: 0x00 */
  uint16_t      RESERVED0;  /*!< Reserved, 0x02                                   */
  __IO uint16_t CR2;        /*!< I2C Control register 2,     Address offset: 0x04 */
  uint16_t      RESERVED1;  /*!< Reserved, 0x06                                   */
  __IO uint16_t OAR1;       /*!< I2C Own address register 1, Address offset: 0x08 */
  uint16_t      RESERVED2;  /*!< Reserved, 0x0A                                   */
  __IO uint16_t OAR2;       /*!< I2C Own address register 2, Address offset: 0x0C */
  uint16_t      RESERVED3;  /*!< Reserved, 0x0E                                   */
  __IO uint16_t DR;         /*!< I2C Data register,          Address offset: 0x10 */
  uint16_t      RESERVED4;  /*!< Reserved, 0x12                                   */
  __IO uint16_t SR1;        /*!< I2C Status register 1,      Address offset: 0x14 */
  uint16_t      RESERVED5;  /*!< Reserved, 0x16                                   */
  __IO uint16_t SR2;        /*!< I2C Status register 2,      Address offset: 0x18 */
  uint16_t      RESERVED6;  /*!< Reserved, 0x1A                                   */
  __IO uint16_t CCR;        /*!< I2C Clock control register, Address offset: 0x1C */
  uint16_t      RESERVED7;  /*!< Reserved, 0x1E                                   */
  __IO uint16_t TRISE;      /*!< I2C TRISE register,         Address offset: 0x20 */
  uint16_t      RESERVED8;  /*!< Reserved, 0x22                                   */
  __IO uint16_t FLTR;       /*!< I2C FLTR register,          Address offset: 0x24 */
  uint16_t      RESERVED9;  /*!< Reserved, 0x26                                   */
} I2C_TypeDef;

某处在功能....

(void) I2C1->SR2;

在此先感谢您的帮助。 本网站已为像我这样的新手一个很好的资源。

Answer 1:

volatile的关键字是为了防止存储器它被优化和/或重新排序访问便携式方式。 应当指出的是,正确使用的volatile关键字使得铸造的表达的结果(void)是不必要的。 举例来说,假设我有一个typedef定义结构和有结构的一个实例。

typedef struct 
{
    int a;
    int b;
}
    SomeStruct;

SomeStruct test;

下面的代码将导致编译器抱怨“警告:表达结果未使用”

    SomeStruct *vptr = &test;
    vptr->a;

我可以通过将结果避免了警告(void) ,但随后的编译器就可以优化掉读取。

    SomeStruct *vptr = &test;
    (void) vptr->a;

但是,如果我宣布指针volatile和不转换为(void) ,我不会得到警告,编译器不会优化掉读取。

    volatile SomeStruct *vptr = &test;
    vptr->a;

这个故事的寓意是,如果你使用的是volatile的关键字,你应该投表达式(void) 。 这只会抑制,否则将识别缺失或不正确使用的警告volatile关键字。



文章来源: Casting the results of a volatile expression to void