我知道volatile关键字会阻止编译器优化变量,并在读取时从内存中读取它。除了内存映射寄存器之外,我们需要使用volatile的所有情况是什么?给定一个符合标准的编译器,我是否必须在两种情况下都将test_var声明为volatile?
int test_var=100;
void func1()
{
test_var++;
}
extern int test_var;
void func2()
{
if(test_var==100)
{
....
}
}
int test_var=100;
void func1()
{
}
extern int test_var;
void func2()
{
if(test_var==100)
{
....
}
}
答案 0 :(得分:6)
内存映射I / O是C中volatile
的唯一泛型用法。*)
使用POSIX信号,volatile
也可以与类型sig_atomic_t
一起使用,如下所示:
volatile sig_atomic_t signal_occured = 0;
您的任何一种方案都不应该要求volatile
。如果你感兴趣的是保证在不同的编译单元之间更新值,请参阅tofro的评论,extern
已经保证了这一点。特别是,volatile
不是正确的工具用于C中的线程同步。它只会引入错误,因为,正如您所说,确实需要实际读取并且写入对变量的访问,但它确实不强制执行关于线程的正确排序(它缺少内存障碍,google了解详细信息)。
请注意,这与其他语言不同,volatile
旨在在线程之间工作。
在嵌入式系统中,volatile
可能足以在ISR(中断服务例程)和主程序之间进行通信,当与原子读取/写入的数据类型结合时,就像{{1}一样对于POSIX信号。请参阅编译器的文档。
*)C标准提到了这一点,以及“异步中断函数”的用例,仅在脚注中,因为内存映射的I / O超出了语言的范围。该语言只是以一种适合内存映射I / O的方式定义sig_atomic_t
的语义。
答案 1 :(得分:4)
在您的两个示例中都不需要volatile
。
volatile
是必要的:
案例1包括:
案例2包括:
以上示例可能并非详尽无遗,但volatile
的语义是关键;该语言只需执行显式访问,如源代码所示。
答案 2 :(得分:1)
除了内存映射设备之类的扩展外,标准C volatile
还有两个用例:与信号处理程序的交互以及setjmp/longjmp
使用对象的修改。两种情况都是因为优化器可能不知道有异常的控制流。
答案 3 :(得分:1)
在使用中断的C单片机应用程序中,volatile
关键字必需,以确保中断中设置的值在中断中正确保存,之后在中断中具有正确的值主要处理循环。未能使用volatile
可能是基于定时器的中断或基于ADC(模数转换)的中断例如在中断后返回处理器状态后恢复控制流时会出现损坏值的最大原因。来自Atmel和GCC的规范模板:
volatile uint8_t flag = 0;
ISR(TIMER_whatever_interrupt)
{
flag = 1;
}
while(1) // main loop
{
if (flag == 1)
{
<do something>
flag = 0;
}
}
如果没有volatile
,则保证不按预期工作。
答案 4 :(得分:0)
除内存映射寄存器外,在什么情况下 我们需要使用挥发物吗?
如果
longjmp
; 那么您可能就不需要挥发了。