volatile 关键字(侵,删)
1、原理作用
volatile意思是“易变的”,在实际工程中,我们应该将其理解为:“直接存取原始内存地址”,“易变”的原因是可能存在外部因素导致volatile修饰的变量随时可能改变,比如中断、多线程等。
volatile在程序设计和编译时怎么起到作用呢?
volatile提醒编译器,它所定义的变量随时都有可能改变,因此编译后的程序每次需要存储后读取这个变量的时候,告诉编译器对该变量不做优化,都会直接从变量内存地址中读取数据,从而可以提供对特殊地址的稳定访问。
如果没有volatile关键字,则编译器可能会优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一样的现象。
2、一般的用途
1)、中断服务程序中修改的供其他程序检测的变量,需要加volatile
当变量在触发某中断程序中修改,而编译器判断主函数里面没有修改该变量,因此可能只执行一次从内存到某寄存器的读操作,而后每次只会从该寄存器中杜群变量副本,使得中断程序的操作被短路。
2)、多任务环境下各任务间共享的标志,应该加volatile
在本次线程内,当读取一个变量时,编译器优化是有时会把变量读取到一个寄存器中,以后,再取变量值时,就直接从寄存器中取值。当内存变量或寄存器变量因别的线程等原因改变值时,该寄存器的值不会响应改变,从而造成了应用程序读取的值和实际的变量值不一致。
###3)、并行设备的硬件寄存器(状态寄存器)
存储器映射的硬件寄存器通常也要加volatile,因为每次对它读写都可能有不同意义。
例如:假设要对一个设备进行初始化,此设备的某一个寄存器为0XF800000 。
int *output = (unsigned int *)0xff800000;//定义一个IO端口;
int init(void)
{
int i;
for(i=0;i< 10;i++){
*output = i;
}
}
经过编译器优化之后,编译器认为前面循环半天都是无效的,对最后结果没有任何影响,因为最终output指向的数据值仍然是9,所以编译器会自动优化执行过程,直接将最后的9赋值,相当于循环括号内只有“* output = 9;”,然而当此时是对外部设备进行初始化,必须依次像上面循环顺序一样对IO口操作,显然此时由于编译器的优化,导致前面的初始化过程没有按照预期输出。反之,读操作,可能也只是读取一次。
我们在学习涉及到嵌入式系统时,由于经常同硬件、中断、RTOS等打交道,所有要求使用volatile修饰的变量,需要我们要特别注意。
3、volatile问题
1)一个参数既可以是const,还可以是volatile吗?
可以。例如只读的状态寄存器。volatile是因为状态寄存器可能会在意想不到的外部状态改变是时改变其内部数据,然而,const保证程序不能改变它
2)指针可以是volatile吗?
可以,当中断服务子程序修改一个指向buffer的指针时。buffer指向一个地址,被A线程修改了这个指向的地址,同时希望B、C等线程也使用这个新地址。
例如,共享指针:
uchar * volatile reg;
代码中,volatile修饰的是reg这个变量。所以,这里实际上定义了一个uchar类型的指针,并且这个指针变量本身是volatile。但是指针指向的内容,并不是volatile,在实际使用的时候,编译器对代码中指针变量reg本身的操作不会进行优化,但是对reg所指向的内容会做non-volatile处理。通常这种写法一般用在对共享指针的声明上面,即这个指针变量可能被中断等修改。
区别于一下表达:
volatile uchar * reg;
这个表示指针指向的内存内容是易变的,而指针地址是普通模式,即编译器在执行该语句时,不会对指针指向的数据优化,但是会对地址指针优化。
volatile用于标记变量可能被外部因素改变,防止编译器优化。它常用于中断服务程序、多线程间的共享标志和并行设备的硬件寄存器。一个变量可以同时是const和volatile,如只读状态寄存器。volatile指针用于中断服务子程序修改的共享指针。文章讨论了volatile的使用场景和潜在问题,强调了其在嵌入式系统中的重要性。
212

被折叠的 条评论
为什么被折叠?



