2014-05-19 17 views
1

注:铸造挥发性表达式的结果作废

这是不是已经被问了很多次同样的事情。是的,我已经阅读了很多关于无效的帖子。这些问题都没有导致答案,我怀疑在这里是正确的。


背景信息:

嵌入式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; 

预先感谢任何帮助。这个网站对于像我这样的新手来说是一个很好的资源。

+0

请注意,如果没有编译器和处理器的制造商/型号,“答案”对您而言可能是正确的。 – KevinDTimm

+0

其实这是我猜这个问题的答案。如果它依赖于编译器,那么这是错误的做法。所以同样的问题略有不同:“是否有独立于编译器的方法来实现相同的目标?”顺便说一下编译器是GCC。 – user1160866

+1

如果访问易失性对象,那么不能通过符合的C编译器优化该访问。 –

回答

2

volatile关键字是便携式方式,以防止内存访问被优化和/或重新排序。应该注意的是,正确使用volatile关键字使得将表达式的结果转换为(void)是不必要的。例如,假设我已经键入了一个结构并拥有该结构的一个实例。

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丢失或不正确的使用。

+0

我想补充说明一下。 – user1160866

+0

我想补充说明一下。它可能并不明显,但在代码片断中,它上面的“__IO”是“volatile”的缩写。另外,我只编译了“I2C1-> SR2”,但没有强制转换,并且使用最高优化设置,并且仍然可以正确生成读取。所以谢谢user3386109。我对此表示满意。好极了! – user1160866

+0

啊,很高兴听到:) – user3386109