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()不会被运行
voliatilekeyword的更多相关文章
随机推荐
- PAT——乙级1026and1046
1026 程序运行时间 (15 point(s)) 要获得一个 C 语言程序的运行时间,常用的方法是调用头文件 time.h,其中提供了 clock() 函数,可以捕捉从程序开始运行到 clock() ...
- 菜鸟之路——机器学习之BP神经网络个人理解及Python实现
关键词: 输入层(Input layer).隐藏层(Hidden layer).输出层(Output layer) 理论上如果有足够多的隐藏层和足够大的训练集,神经网络可以模拟出任何方程.隐藏层多的时 ...
- FastDFS的安装(复制自己用)
FastDFS 安装及使用 FastDFS 安装及使用 2012-11-17 13:10:31| 分类: Linux|举报|字号 订阅 Google了一下,流行的开源分布式文件系统有很多,介 ...
- iis特殊后缀文件下载404
项目中有特殊类型的文件上传到服务器,下载的时候报404,下载不下来.如后缀名为qwwq这种类型. 因为遇到过这种情况,以前都是配置mime类型好的,但是这次没有找到,到底应该配置什么mime类型,一时 ...
- 201621123034 《Java程序设计》第1周学习总结
1. 本周学习总结 知道了java的用途有安卓手机应用,企业服务器后端,java web.学到了新概念:类.HelloWorld.java 中 HelloWorld 是主文件名,区分 .java和 . ...
- 项目记事【StreamAPI】:使用 StreamAPI 简化对 Collection 的操作
最近项目里有这么一段代码,我在做 code-review 的时候,觉得可以使用 Java8 StreamAPI 简化一下. 这里先看一下代码(不是源码,一些敏感信息被我用其他类替代了): privat ...
- Moscow Pre-Finals Workshop 2016. Japanese School OI Team Selection. 套题详细解题报告
写在前面 谨以此篇题解致敬出题人! 真的期盼国内也能多出现一些这样质量的比赛啊.9道题中,没有一道凑数的题目,更没有码农题,任何一题拿出来都是为数不多的好题.可以说是这一年打过的题目质量最棒的五场比赛 ...
- [openjudge6043]哆啦A梦的时光机
[openjudge6043]哆啦A梦的时光机 试题描述 哆啦A梦有一个神奇的道具:时光机.坐着它,大雄和他的伙伴们能穿越时空,回到过去或者去到未来. 有一天,大雄和他的伙伴们想穿越时空进行探险,可是 ...
- leetcode 389 map iterator 的使用
class Solution { public: char findTheDifference(string s, string t) { map<char,int>Map_Temp; ; ...
- 【15】vuex2.0 之 modules
vue 使用的是单一状态树对整个应用的状态进行管理,也就是说,应用中的所有状态都放到store中,如果是一个大型应用,状态非常多, store 就会非常庞大,不太好管理.这时vuex 提供了另外一种方 ...