| 
 | 
	
    
 
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册  
 
x
 
volatile修饰的变量是说这变量可能会被意想不到地改变。通常对于程序员而言,单片机中用的就算常见了。 
( s; @/ K+ y, s9 e# b& Q2 L8 q5 r* v2 o 
0 T+ o  {9 W" |) G& b- gvolatile 是易变的,不稳定的意思。其实对于很多人来说,根本没见过这个关键字,不知道它的存在。也有很多人知道它的存在,根本没用过,我对它有种“杨家有女初长成,养在深闺无人识”的感觉。; Z( ]- O- |4 ?9 ~) [- v- y# _ 
5 l  ^3 ^+ T% {! v/ ?$ A  p 
那么volatile关键字到底是什么意思呢,怎么用呢?. I8 F( G0 `* l( E4 j: U; f/ r$ [2 U 
* ]" P. ~/ v5 m0 b& [/ y 
1、volatile其实和const一样是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素而改变,比如操作系统、硬件或者其他线程等等。遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问。 
9 P$ c6 \. ^! J- b) k# ^ 
& V3 l* @3 t0 {4 X7 I. [①我们举个例子:  s+ B3 n9 J- A/ p' o/ M 
int i=10; 
0 s2 J' f! z% D/ Gint j=i; //①语句: g) `& H" R$ a% S0 l 
int k=i; //②语句/ [& G. J& e5 m( \' Y1 u& E 
 
* y& M- f  w, x# e3 h' H! ?  f此时编译器对代码进行优化,这是因为在①、②两条语句中,i没有被用作左值(没有被赋值),这时候编译器认为是i的值没有发生改变,所以在①语句时从内存中取出i的值赋给j之后,这个值并没有被丢掉,而是在②语句时继续用这个值给k赋值。编译器不会生成出汇编代码重新从内存里取i的值(不会编译生成装在内存的汇编指令,比如ARM的LDM指令),这样提高了效率。但要注意①和②语句之间确认i没有被用作左值才行。9 }+ [. q& b3 ~5 | 
 
7 l8 {/ t+ X* T( j8 n②再看一个例子:; h# f/ i5 A1 M- l6 A8 L 
volatile int i=10;+ C7 r  f/ l9 O1 O; V, e 
int j=i;   //③语句 
* O0 b+ ^; p7 b* z  d+ W- L" nint k = i;   //④语句( u% {( g# B* l+ \6 g 
* U1 y+ l3 W4 q9 x2 W! i9 l4 y 
volatile关键字告诉编译器,i是随时可能发生改变的。每次使用它的时候必须从内存中取出i的值,因而编译器生成的汇编代码会重新从i的地址处读取数据放在k中。/ o" r; E6 _. Z 
7 U$ @0 ^) r6 [7 J2 E7 z8 A 
这样看来,如果i是一个寄存器变量,表示一个端口数据或者是多个线程的共享数据,那么就容易出错,所以说,volatile可以保证对特殊地址的稳定访问。 
9 u+ I5 B% y! N5 d5 @8 M8 L$ H 
6 n. Q5 h! U! Y, H2、我们知道做电子方面技术工作的一般面试的时候都有笔试,比如单片机软件方面,考题基本都会有对这个关键字的考察,可想在单片机中这个关键字的重要性,一般题目会有对这个关键字的定义是什么,就是你得知道它的概念,然后就是举例说明这个关键字使用的例子,这个时候就能考察出大家对这个关键字的具体理解了。 
+ t$ x- Q( Y9 A 
& a3 I- E$ a+ q6 ?一般我们知道的是:3 K; e. b0 e9 `5 T% H 
①并行设备的硬件寄存器(比如状态寄存器) 
6 \. B( z* j) G- a& U8 P+ S5 x% }②一个中断服务子程序中会访问到的非自动变量4 ?0 _3 i8 E8 n( |& g 
③多线程应用中被几个任务共享的变量 
" \" s) H9 h9 z& {9 c2 b' ?3 `+ r 
/ m& H1 r. h6 T4 f( t$ G$ [3 v. {' O  ]  N 
当我们回答出这些时基本可以知道你对这个关键字是懂的,如果做嵌入式的话,程序员经常和硬件、中断、RTOS等等打交道,所以这个关键字必须要懂。( a* l3 E" l, u# d/ @; V 
, R' [6 _  [! w  q$ R 
3、那么我们再延伸一下,一个参数既可以是const也可以是volatile,那么举个例子就是只读的状态寄存器,那么只读就是const,并且要确定程序不能试图去修改它,再有就是volatile代表状态寄存器,可能被意想不到的改变。 
9 r' Z1 S; {5 s: ?2 t2 @* E% z5 q: f0 [ 
4、那么指针是不是可以用到这个volatile关键字吗,是可以的。 
. e4 u& X/ y$ [& C7 O6 R/ ^7 m. Z这个我们只要了解即可,用的不多。但是得知道。举个例子就是当一个中断服务子程序修改一个指向一个buffer的指针的时候。修饰也和const类似,const有常量指针和指针常量的说法,volatile也可以这样认为,比如修饰由指针指向的对象或数据是const或volatile的。* w! R5 Z- q6 d" _8 C 
 
. _+ S1 a3 S6 N' d  m! m例如:  [2 G2 n$ _9 F: u( o, t 
volatile  char  *p1;, H# A, ]+ U- V. T* y/ Q6 _# N& q 
比如指针自身的值---一个代表地址的整数变量是const或volatile的。 
# A( W% i! o9 z+ N  G1 ]  S3 D4 E- P( L! H' U: l/ s( M9 }# C 
例如: 
1 ~1 \4 M- g9 P9 ichar*  volatile  p1;5 r/ W8 O( o8 f+ j4 r  S2 e 
对于这个关键字不仅C语言有,其他语言比如C++,JAVA其实都有。其他语言大部分是因为多线程共享变量的使用不被编译器优化的错误产生,比如优化编译器把一个变量从内存装入CPU寄存器中,那么两个线程有可能一个使用内存中的变量,一个使用寄存器中的变量,这回造成程序的错误执行。那么用了volatile来修饰变量了呢就是要告诉编译器每次操作这个变量的时候一定要从内存中真正取出,而不是使用已经存在寄存器的值。) D* E9 m6 F7 Z 
; z; r: X4 o. j" N  ~8 m# t 
对于volatile怎么修饰变量,什么变量需要这个关键字修饰,大家心里有数了吧? 
3 Z' p! o$ K) a  H# |# W |   
 
 
 
 |