您的位置 首页 方案

关于全局变量被修正以及volatile的用法

今天调一个程序的时候发现一个事情,就是全局变量在中断中被改变,代码如下unsignedcharnum=0;INTERRUPT(){num++;}v

今日调一个程序的时分发现一个工作,便是全局变量在中止中被改动,代码如下

…..

unsigned char num=0;

…..

INTERRUPT()

{

….

num++;

….

}

void main()

{

out(num);

}

很不幸的工作是在主函数中,num一向都不会变,编译器avrstdio,外部中止。

调试中发现中止时能够进去的,可是中止出来今后,这个全局变量就被改动了,后来加了volitale就能够了。。

下面说说volatile的详细用法(以下内容都是摘录):

volatile的字面意思为“不安稳的,易变的”

volatile关键字是一种类型修饰符,用它声明的类型变量标明能够被某些编译器不知道的要素更改。

用volatile关键字声明的变量i每一次被拜访时,履行部件都会从i相应的内存单元中取出i的值。

没有用volatile关键字声明的变量i在被拜访的时分或许直接从cpu的寄存器中取值(因为之前i被拜访过,也便是说之前就从内存中取出i的值保存到某个寄存器中),之所以直接从寄存器中取值,而不去内存中取值,是因为编译器优化代码的成果(拜访cpu寄存器比拜访ram快的多)。

以上两种状况的差异在于被编译成汇编代码之后,两者是不一样的。之所以这样做是因为变量i或许会常常改动,确保对特别地址的安稳拜访。

volatile关键字是一种类型修饰符,用它声明的类型变量标明能够被某些编译器不知道的要素更改,比方:操作体系、硬件或许其它线程等。遇到这个关键字声明的变量,编译器对拜访该变量的代码就不再进行优化,然后能够供给对特别地址的安稳拜访。

运用该关键字的比如如下:
volatile int i;
当要求运用volatile声明的变量的值的时分,体系总是从头从它地点的内存地址读取数据,即便它前面的指令刚刚从该处读取过数据,并且读取的数据马上被保存。

例如:
volatile int i = 10;
int a = i;

//其他代码,并未清晰告知编译器,对i进行过操作
int b = i;

volatile指出i是随时或许发生改动的,每次运用它的时分有必要从i的地址中读取,因此编译器生成的汇编代码会从头从i的地址读取数据放在b中。而优化的做法是,因为编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会主动把前次读的数据放在b中,而不是从头从i的地址中读取。这样一来,假如i是一个寄存器变量或许标明一个端口数据就简单犯错,所以说volatile能够确保对特别地址的安稳拜访。

留意,在VC6中,一般调试形式没有进行代码优化,所以这个关键字的效果看不出来。下面经过刺进汇编代码,测验有无volatile关键字,对程序终究代码的影响:

首要,用classwizard建一个win32 console工程,刺进一个voltest.cpp文件,输入下面的代码:
 
#include

void main() {
int i = 10;
int a = i;
printf(“i = %d”, a);
// 下面汇编句子的效果便是改动内存中i的值,可是又不让编译器知道
__asm {
mov dword ptr [ebp-4], 20h
}

int b = i;
printf(“i = %d”, b);
}

然后,在调试版别形式运转程序,输出成果如下:
i = 10
i = 32

然后,在release版别形式运转程序,输出成果如下:
i = 10
i = 10

输出的成果显着标明,release形式下,编译器对代码进行了优化,第2次没有输出正确的i值。

下面,咱们把i的声明加上volatile关键字,看看有什么改动:

#include

void main() {
volatile int i = 10;
int a = i;
printf(“i = %d”, a);
// 下面汇编句子的效果便是改动内存中i的值,可是又不让编译器知道
__asm {
mov dword ptr [ebp-4], 20h
}

int b = i;
printf(“i = %d”, b);
}

分别在调试版别和release版别运转程序,输出都是:
i = 10
i = 32

这说明这个关键字发挥了它的效果!

================================

将一个变量说明为volatile标明这个变量是“易变的”。假如一个变量会被其它引证改动,或在其它并行的使命中会被改动(例如中止服务程序),都要显式地说明为“volatile”,不然在编译器优化阶段会作犯过错的判别,例如将这个变量读入寄存器今后,在没有对这个变量赋值曾经,会一向运用寄存器中的值,而实际上这个变量的值或许现已被一个指针引证改动了,或许是在中止服务程序中被改动了,下面这个比如说明晰这种过错:

有一个变量T,在守时中止中每隔一个固守时刻减一,然后在主程序中等候它减到0。

unsigned char T;
void T0_int(void) interrupt 1 {

T–;

}

void main(void)
{

T=10;
while (T!=0);

}

正确的写法应该是将榜首句改为:
volatile unsigned char T;

从上面这个比如中很不幸的看到,在中止中改动的这个数值假如不请求成volatile的话,被优化今后就麻烦了。。。

这个在嵌入式环境中特别重要。。好吧。。难。。今后要留意一下~~~~~

2011.5.26新加:

比如:串口经过中止承受一个字节数据,然后在中止中把这个数据存到一个缓冲区中,等候运用。当主程序中需求读出数据时,就去读缓冲区。此刻缓冲区的声明应该是

volitale unsigned char rxbuf[SIZE]; 需求将关键字加上,不然缓冲区中读出的数据或许不会对,榜首个字节来的时分,再加一个延时,等候数据完结即可。

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/fangan/260919.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部