voliatilekeyword

啃书的时候,发现了这个keyword。 曾经都没有听过。唉,我真是孤陋寡闻啊。。。

 C/C++ 中的 volatile keyword和 const 相应,用来修饰变量,通经常使用于建立语言级别的 memory barrier。这是 BS 在 "The C++ Programming Language" 对 volatile 修饰词的说明:

A volatile specifier is a hint to a compiler that an object may change its value in ways not specified by the language so that aggressive optimizations must be avoided.

      volatile keyword是一种类型修饰符,用它声明的类型变量表示能够被某些编译器未知的因素更改。比方:操作系统、硬件或者其他线程等。

遇到这个keyword声明的变量,编译器对訪问该变量的代码就不再进行优化,从而能够提供对特殊地址的稳定訪问。声明时语法:int volatile vInt; 当要求使用 volatile 声明的变量的值的时候,系统总是又一次从它所在的内存读取数据,即使它前面的指令刚刚从该处读取过数据。并且读取的数据立马被保存。比如: 1 volatile int i=10; 2 int a = i; 3 ... 4 // 其他代码,并未明白告诉编译器,对 i 进行过操作 5 int b = i; volatile 指出 i 是随时可能发生变化的,每次使用它的时候必须从 i的地址中读取。因而编译器生成的汇编代码会又一次从i的地址读取数据放在 b 中。而优化做法是。由于编译器发现两次从 i读数据的代码之间的代码没有对 i 进行过操作,它会自己主动把上次读的数据放在 b 中。而不是又一次从 i 里面读。

这样以来,假设 i是一个寄存器变量或者表示一个port数据就easy出错,所以说 volatile 能够保证对特殊地址的稳定訪问。注意,在 VC 6 中,一般调试模式没有进行代码优化,所以这个keyword的作用看不出来。以下通过插入汇编代码,測试有无 volatile keyword,对程序终于代码的影响: 输入以下的代码: 01 #include <stdio.h> 02 03 void main() 04 { 05 int i = 10; 06 int a = i; 07 08 printf("i = %d", a); 09 10 // 以下汇编语句的作用就是改变内存中 i 的值 11 // 可是又不让编译器知道 12 __asm { 13 mov dword ptr [ebp-4], 20h 14 } 15 16 int b = i; 17 printf("i = %d", b); 18 } 然后。在 Debug 版本号模式运行程序,输出结果例如以下: i = 10 i = 32 然后。在 Release 版本号模式运行程序。输出结果例如以下: i = 10 i = 10 输出的结果明显表明,Release 模式下。编译器对代码进行了优化,第二次没有输出正确的 i 值。

以下,我们把 i 的声明加上 volatile keyword。看看有什么变化: 01 #include <stdio.h> 02 03 void main() 04 { 05 volatile int i = 10; 06 int a = i; 07 08 printf("i = %d", a); 09 __asm { 10 mov dword ptr [ebp-4], 20h 11 } 12 13 int b = i; 14 printf("i = %d", b); 15 } 分别在 Debug 和 Release 版本号运行程序。输出都是: i = 10 i = 32 这说明这个 volatile keyword发挥了它的作用。事实上不仅仅是“内嵌汇编操纵栈”这种方式属于编译无法识别的变量改变,另外很多其他的可能是多线程并发訪问共享变量时,一个线程改变了变量的值,如何让改变后的值对其他线程 visible。

一般说来。volatile用在例如以下的几个地方: 1) 中断服务程序中改动的供其他程序检測的变量须要加volatile; 2) 多任务环境下各任务间共享的标志应该加volatile。 3) 存储器映射的硬件寄存器通常也要加volatile说明,由于每次对它的读写都可能由不允许义; 2.volatile 指针 和 const 修饰词相似。const 有常量指针和指针常量的说法,volatile 也有相应的概念: 修饰由指针指向的对象、数据是 const 或 volatile 的: 1 const char* cpch; 2 volatile char* vpch; 注意:对于 VC,这个特性实如今 VC 8 之后才是安全的。

指针自身的值——一个代表地址的整数变量,是 const 或 volatile 的: 1 char* const pchc; 2 char* volatile pchv; 注意:(1) 能够把一个非volatile int赋给volatile int。可是不能把非volatile对象赋给一个volatile对象。    (2) 除了基本类型外。对用户定义类型也能够用volatile类型进行修饰。 (3) C++中一个有volatile标识符的类仅仅能訪问它接口的子集,一个由类的实现者控制的子集。

用户仅仅能用const_cast来获得对类型接口的全然訪问。

此外,volatile向const一样会从类传递到它的成员。 3. 多线程下的volatile 有些变量是用volatilekeyword声明的。

当两个线程都要用到某一个变量且该变量的值会被改变时,应该用volatile声明,该keyword的作用是防止优化编译器把变量从内存装入CPU寄存器中。

假设变量被装入寄存器。那么两个线程有可能一个使用内存中的变量。一个使用寄存器中的变量,这会造成程序的错误运行。

volatile的意思是让编译器每次操作该变量时一定要从内存中真正取出。而不是使用已经存在寄存器中的值,例如以下: volatile BOOL bStop = FALSE; (1) 在一个线程中: while( !bStop ) { ... } bStop = FALSE; return; (2) 在另外一个线程中。要终止上面的线程循环: bStop = TRUE; while( bStop ); //等待上面的线程终止,假设bStop不使用volatile申明,那么这个循环将是一个死循环。由于bStop已经读取到了寄存器中,寄存器中bStop的值永远不会变成FALSE,加上volatile,程序在运行时,每次均从内存中读出bStop的值。就不会死循环了。 这个keyword是用来设定某个对象的存储位置在内存中,而不是寄存器中。由于一般的对象编译器可能会将其的拷贝放在寄存器中用以加快指令的运行速度,比例如以下段代码中: ... int nMyCounter = 0; for(; nMyCounter<100;nMyCounter++) { ... } ... 在此段代码中,nMyCounter的拷贝可能存放到某个寄存器中(循环中,对nMyCounter的測试及操作总是对此寄存器中的值进行),可是另外又有段代码运行了这种操作:nMyCounter -= 1;这个操作中,对nMyCounter的改变是对内存中的nMyCounter进行操作。于是出现了这样一个现象:nMyCounter的改变不同步。


volatile 影响编译器编译的结果,指出。volatile 变量是随时可能发生变化的。与volatile变量有关的运算,不要进行编译优化,以免出错。(VC++ 在产生release版可运行码时会进行编译优化,加volatilekeyword的变量有关的运算,将不进行编译优化。)。 
比如: 
volatile int i=10; 
int j = i; 
... 
int k = i; 
volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可运行码会又一次从i的地址读取数据放在k中。

而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自己主动把上次读的数据放在k中。

而不是又一次从i里面读。这样以来,假设i是一个寄存器变量或者表示一个port数据就easy出错,所以说volatile能够保证对特殊地址的稳定訪问,不会出错。 /********************** 一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是。优化器在用到这个变量时必须每次都小心地又一次读取这个变量的值。而不是使用保存在寄存器里的备份。

以下是volatile变量的几个样例: 1) 并行设备的硬件寄存器(如:状态寄存器) 2) 一个中断服务子程序中会訪问到的非自己主动变量(Non-automatic variables) 3) 多线程应用中被几个任务共享的变量 回答不出这个问题的人是不会被雇佣的。我觉得这是区分C程序猿和嵌入式系统程序猿的最主要的问题。搞嵌入式的家伙们经常同硬件、中断、RTOS等等打交道。全部这些都要求用到volatile变量。不懂得volatile的内容将会带来灾难。假设被面试者正确地回答了这是问题(嗯,怀疑是否会是这样),我将略微深究一下,看一下这家伙是不是直正懂得volatile全然的重要性。 1)一个參数既能够是const还能够是volatile吗?解释为什么。

2); 一个指针能够是volatile 吗?解释为什么。 3); 以下的函数有什么错误: int square(volatile int *ptr) { return *ptr * *ptr; } 以下是答案: 1)是的。一个样例是仅仅读的状态寄存器。它是volatile由于它可能被意想不到地改变。

它是const由于程序不应该试图去改动它。

2); 是的。虽然这并不非经常见。一个样例是当一个中服务子程序修该一个指向一个buffer的指针时。 3) 这段代码有点变态。

这段代码的目的是用来返指针*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; } 位操作(Bit manipulation) //********************* 嵌入式编程中经经常使用到 volatile这个keyword,使用方法能够归结为以下两点: 一:告诉compiler不能做不论什么优化 比方要往某一地址送两指令: int *ip =...; //设备地址 *ip = 1; //第一个指令 *ip = 2; //第二个指令 以上程序compiler可能做优化而成: int *ip = ...; *ip = 2; 结果第一个指令丢失。

假设用volatile, compiler就不允许做不论什么的优化。从而保证程序的原意: volatile int *ip = ...; *ip = 1; *ip = 2; 即使你要compiler做优化。它也不会把两次付值语句间化为一。它仅仅能做其他的优化。

这对device driver程序猿非常实用。

二:表示用volatile定义的变量会在程序外被改变,每次都必须从内存中读取。而不能把他放在cache或寄存器中反复使用。 如 volatile char a; a=0; while(!a){ //do some things; } doother(); 假设没有 volatile doother()不会被运行


【推广】 免费学中医,健康全家人
原文地址:https://www.cnblogs.com/zhchoutai/p/8653970.html