volatile那些事 集成开发环境

admin 4月前 305

总是碰到客户求助,调试仿真时某个变量明明在其他地方已经赋值,但程序执行就是不对,并且监视窗口看到的值也不正常。这不,今天又来一个友商, 某个标志位变量明明中断服务程序中已置了1,中断也执行了,主程序的判断里就认为它是0,这问题昨儿折腾了他一下午,实在是百思不得其解,今儿一早就赶着“寻医问诊”来啦。 粗略了解了下他的程序架构,并看了现象后,让他在变量定义前加volatile修饰,于是问题立马解决, 顿时有种妙手回春的感觉~~觉得该写写关于volatile的那些事了。


volatile意即易挥发的,易变的,其实应该解释为“直接存取原始内存地址”比较合适,“易变的”这种解释简直有点误导人;“易变”是因为外在因素引起的,而中断等并不是因为用了volatile修饰了的变量就是“易变”了,假如没有外因,即使用volatile定义,它也不会变化;而用volatile定义之后,其实是这个变量就不会因外因而变化了,可以放心使用了,或者说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。


volatile关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改,比如:操作系统、硬件或者其它线程等。遇到这个关键字声明的变量,编译器对访问该变量的代码就会进行优化,从而可以提供对特殊地址的稳定访问。Volatile类型修饰符作为指令关键字,会确保本条指令不会因编译器的优化而省略,且要求每次直接读值。 使用该关键字的例子如下:

volatile int vint;

用volatile修饰是为了防止编译器对代码进行优化。比如如下程序:

XBYTE[2]=0x55;
XBYTE[2]=0x56;
XBYTE[2]=0x57;
XBYTE[2]=0x58;

对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器却会对上述四条语句进行优化,认为只有

XBYTE[2]=0x58

(即忽略前三条语句,只产生一条机器代码)。如果键入volatile,则编译器会逐一地进行编译并产生相应的机器代码(产生四条代码)。准确的说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。

下面是使用volatile变量的几个例子:

  1. 并行设备的硬件寄存器(如:状态寄存器)
  2. 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
  3. 多线程应用中被几个任务共享的变量总结:

总结:

对于嵌入式软件开发者来说需经常和硬件、中断、RTOS等等打交道,所以:

  1. 中断服务程序中修改的供其它程序检测的变量需要加volatile;
  2. 多任务环境下各任务间共享的标志应该加volatile;
  3. 存储器映射的硬件寄存器通常也要加volatile说明,因为每次对它的读写都可能有不同意义;

如上情况如果不知道使用volatile变量,将会带来意想不到的莫名现象。


最新回复 (0)
返回