注意:
这与已被问过多次的问题不同。是的,我读过很多关于类型转换无效的帖子。这些问题都没有得出我怀疑的答案。
背景信息:
嵌入式 C。这与内存映射 volatile 指针特别相关。换句话说,外设寄存器。
我在涉及写入 I2C 外设的例程中遇到了以下行:
(void) I2C1->SR2;
I2C1
#定义为 volatile 内存的结构*。
所以这一行的结果不是“避免编译器警告”,就像我在这里所做的所有搜索的答案一样。事实上,它导致编译器读取该寄存器(因为它是 volatile 的),然后将其丢弃。该寄存器中有标志。读取寄存器的操作会导致标志被清除。
现在这非常重要,因为目标是清除标志而不仅仅是避免一些编译器警告!
然而,让我担心的是,在某种程度的优化或者不同的编译器下,这段代码将会被优化掉。这就是我的问题:这会被优化掉还是有办法保证它不会被优化掉?
我将所有相关代码放在一起如下:
#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;
预先感谢您的帮助。对于像我这样的新手来说,这个网站是一个很好的资源。
最佳答案
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
关键字的丢失或不正确使用。
关于将 volatile 表达式的结果转换为 void,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23746870/