打印

关于volatile很纠结!

[复制链接]
7079|22
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
areshan|  楼主 | 2011-6-17 18:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
用AVR的studio时,发现用volatile unsigned char,和unsigned char 不一样!怎么不一样呢?用指向unsigned char的指针指向volatile unsigned char 数据是有警告:../main.c:259: note: expected 'unsigned char *' but argument is of type 'volatile unsigned char *'
这个让我很纠结,我到底是在中断的全局变量前加volatile还是不加呢?纠结中。。。
volatile uchar usart_buf[30]={0};
char mm(unsigned char *pdata,unsigned char n)
{
    unsigned char i,lrc=0;
    for(i=0;i<n;i++)
    {
        lrc+=*(pdata+i);
        }
    return 0;
    }
int main(void)
{
     mm(usart_buf,10);
     return 0;
}
上面的代码只是举例,看着有警告,心里不爽快,想着中断里没有volatile心里不踏实,让我纠结呀!!!!!!

相关帖子

沙发
areshan|  楼主 | 2011-6-17 18:07 | 只看该作者
不知道各位有没有比这个更让人纠结的呢?

使用特权

评论回复
板凳
hgjinwei| | 2011-6-17 22:44 | 只看该作者
什么乱七八糟的程序啊,既然可以不加任何保护措施就这样整段拷贝,那就算不上"volatile”;
如果真是"volatile",那拷贝时就要加以保护,防止拷贝期间数据变更。

使用特权

评论回复
地板
李冬发| | 2011-6-17 23:52 | 只看该作者
在中断的全局变量前必须加volatile!

使用特权

评论回复
5
hotpower| | 2011-6-18 01:06 | 只看该作者
在中断的全局变量前必须加volatile!
李冬发 发表于 2011-6-17 23:52


同意

使用特权

评论回复
6
areshan|  楼主 | 2011-6-18 08:28 | 只看该作者
加了用unsigned char *pdata指向unsigned char data是会有警告!谢谢大家,我也知道该加,但是警告怎么弄呢?
我把指针变成volatile unsigned char *pdata,有这样的指针吗??????

使用特权

评论回复
7
xwj| | 2011-6-18 08:42 | 只看该作者
3楼正解,这时编译器给出警告是对的,不警告才不对。


如果你觉得没问题,也可以忽视警告。

使用特权

评论回复
8
areshan|  楼主 | 2011-6-18 08:47 | 只看该作者
谢谢xwj,不懂3楼说的可以防止数据在拷贝期间被变更。。。。。。。。。。
数据在执行期间被变更我认为是在中断里不小心改变了数据,防止数据变更需要关中断!
我对volatile的理解是防止变量被编译器优化掉。

使用特权

评论回复
9
cecwxf| | 2011-6-18 14:34 | 只看该作者
防止编译器优化掉

使用特权

评论回复
10
armmage| | 2011-6-18 15:28 | 只看该作者
在中断的全局变量前必须加volatile?        
麻烦大侠说具体点,为啥这样做?一定有必要?
我记得volatile用来 修饰访问MCU寄存器的绝对地址最好不过了,尤其是IO口读写的
比如 #define PINSEL0         (*((volatile unsigned long *) 0xE002C000))
因为IO口状态读写最容易被编译器优化成从最近使用过的MCU的R寄存器中读取值,而不是从IO口固定地址读取,并且读取的是有IO口电平状态可能有变,这样就不能保证读取到真实值,但是说在中断的全局变量前必须加volatile,麻烦指教下为什么必须 我绝对全局变量这种东西死占着内存不放,编译器每次应该都是从内存读取,不会找捷径从R寄存器读取,似乎没有必要用volatile保护,不话说多写个保护也不少块肉,我只是纠结这么做到底在什么情况下能起到保护。

使用特权

评论回复
11
armmage| | 2011-6-18 15:29 | 只看该作者
打字快了错字多······

使用特权

评论回复
12
areshan|  楼主 | 2011-6-18 15:40 | 只看该作者
 推荐一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子:
  1). 并行设备的硬件寄存器(如:状态寄存器)
  2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
  3). 多线程应用中被几个任务共享的变量
  回答不出这个问题的人是不会被雇佣的。我认为这是区分C程序员和嵌入式系统程序员的最基本的问题。嵌入式系统程序员经常同硬件、中断、RTOS等等打交道,所用这些都要求volatile变量。不懂得volatile内容将会带来灾难。

上面是baidu的百科里的解释,下面有网址,有很详细的说volatile,供大家一起学习。
http://baike.baidu.com/view/608706.htm

使用特权

评论回复
13
areshan|  楼主 | 2011-6-18 15:50 | 只看该作者
我想volatile的核心就是和编译器做斗争,让编译器不要偷懒(读寄存器的值),而应该重新去变量地址取值。。。。。。

使用特权

评论回复
14
areshan|  楼主 | 2011-6-18 15:51 | 只看该作者
问题的关键是编译器为什么要先读寄存器里有的值呢?????这个可能要涉及到编译原理等一系列的规则在里面!不懂,求解释!:lol

使用特权

评论回复
15
ahgao| | 2011-6-18 16:50 | 只看该作者
很简单,比如
while (timer < 100);
这是一个延时循环,timer在中断中做累加。如果timer是volatile的,编译器每次都会去获取内存中的变量值,它是被中断程序不断改写的。如果timer不是volatile的,在一般的优化编译环境下,编译器会使用寄存器的值,而这个值是不会变得,延时变成了死循环。
为什么编译器要这么处理?因为编译器是很笨的,它不会知道看上去不会改变值的timer实际上是会变化的,因此它为了优化速度和代码量,它会把timer的值读一次后一直使用,这就是为什么你必须用volatile告诉编译器不要这么干。
同理,硬件接口的寄存器也是必须用volatile定义的。

使用特权

评论回复
16
areshan|  楼主 | 2011-6-18 17:47 | 只看该作者
楼上的解释有些道理,但是那个例子的意思是这样的吗???????
例1:
unsigned int timer=0;  //timer不是volatile的
while(timer<100)
{
     timer++;
}     //是死循环吗?
例2:
volatile unsigned int timer=0; //timer是volatile类型的
while(timer<100)
{
     timer++;
}   //这个不是死循环,因为timer一直在变,而编译器每次都在timer地址读值

这里有也试过2个例子,但是都不是死循环。

使用特权

评论回复
17
areshan|  楼主 | 2011-6-18 17:48 | 只看该作者
不知道是不是我理解错!还希望能够开导一下!

使用特权

评论回复
18
ahgao| | 2011-6-18 17:53 | 只看该作者
本帖最后由 ahgao 于 2011-6-18 18:33 编辑

我写的是while ( timer < 100); 有分号的,没有循环体timer++。

使用特权

评论回复
19
areshan|  楼主 | 2011-6-18 17:57 | 只看该作者
所有的C中的代码都最终会被编译器编译成汇编,汇编大家都应该很熟悉吧,MOV R0,#0X11之类的,汇编没有那么多的寄存器去给每个变量用,所以C中的变量都是其实都是放在ram里的,每个变量名对应一个地址,要用该变量的时候,用mov r0,【变量地址】,把变量读到寄存器中。这样可以在寄存器里操作变量,同时你也可以用mov [变量地址],R0,直接去地址里改变变量。如果你把变量读到了寄存器,而用在地址里去改变了变量,这就造成了变量的不同步,所以要约定每次都是要从地址中去取值,这样可以保证变量的同步。。。。。。
不知道这样理解对不对!!!!!!

使用特权

评论回复
20
areshan|  楼主 | 2011-6-18 18:00 | 只看该作者
哦,原来是这样:
unsigned int timer=0;
ISR() //中断函数
{
timer++;
}
main()
{
while(time<100); //死循环
}
原来是这样,谢谢ahgao!!!!!!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

127

主题

728

帖子

0

粉丝