现在的位置: 首页 > 综合 > 正文

深入理解C++中的volatile关键字

2017年10月04日 ⁄ 综合 ⁄ 共 1717字 ⁄ 字号 评论关闭

          

深入理解C++中的volatile关键字

kezunhai@gmail.com

http://blog.csdn.net/kezunhai

         就像大家更熟悉的const一样,volatile是一个类型修饰符(type specifier)。它是被设计用来修饰被不同线程访问和修改的变量。如果没有volatile,基本上会导致这样的结果:要么无法编写多线程程序,要么编译器失去大量优化的机会。

        volatile的本意是“易变的” 因为访问寄存器要比访问内存单元快的多,所以编译器一般都会作减少存取内存的优化,但有可能会读脏数据。当要求使用volatile声明变量值的时候,系统总是重新从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。精确地说就是,遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问;如果不使用valatile,则编译器将对所声明的语句进行优化。(简洁的说就是:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错。加了volatile修饰的变量,编译器将不对其相关代码执行优化,而是生成对应代码直接存取原始内存地址)。

        volatile的作用: 作为指令关键字,确保本条指令不会因编译器的优化而省略,且要求每次直接读值。简单地说就是防止编译器对代码进行优化.比如如下程序:

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

对外部硬件而言,上述四条语句分别表示不同的操作,会产生四种不同的动作,但是编译器却会对上述四条语句进行优化,认为只有XBYTE[2]=0x58(即忽略前三条语句,只产生一条机器代码)。如果键入volatile,则编译器会逐一的进行编译并产生相应的机器代码(产生四条代码)。

         一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。一般说来,volatile用在如下的几个地方:

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

这是区分C程序员和嵌入式系统程序员的最基本的问题:嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所有这些都要求使用volatile变量。不懂得volatile内容将会带来灾难。

       下面的函数被用来计算某个整数的平方,它能实现预期设计目标吗?如果不能,试回答存在什么问题:

	int square(volatile int*ptr)
	{
		return*ptr**ptr;
	}

这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码:

	int square(volatile int*ptr)
	{
		int a,b;
		a=*ptr;
		b=*ptr;
		return a*b;
	}

由于*ptr的值可能在两次取值语句之间发生改变,因此a和b可能是不同的。结果,这段代码可能返回的不是你所期望的平方值!正确的代码如下:

	long square(volatile int*ptr)
	{
		int a;
		a=*ptr;
		return a*a;
	}

     
注意:频繁地使用volatile很可能会增加代码尺寸和降低性能,因此要合理的使用volatile    


参考资料:

1、volatile百科

2、C/C++要点全掌握(五)——mutable、volatile

3、C语言中volatile关键字的作用

作者:kezunhai出处:http://blog.csdn.net/kezunhai欢迎转载或分享,但请务必声明文章出处

抱歉!评论已关闭.