打印

C的关键字volatile有一条没有理解,请教

[复制链接]
5125|33
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
misra|  楼主 | 2012-7-31 08:42 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
volatile变量主要用在以下几个方面:
(1)并行设备的硬件寄存器(如状态寄存器);
(2)一个中断服务子程序中会访问到的非自动变量;
(3)多线程应用中被几个任务共享的变量。

请问第二点是啥意思?

我自认为C水平不错。
其中第一点能明白。第三点关于操作系统暂且不管。

请问第二点啥意思?

我现在看到有说法是:   
编译器只对main下面的全局变量感兴趣,所以就忽视了中断服务里面的全局变量。
但是我现在并没有发现keil忽视了中断服务程序的全局变量啊。

在keil下是不是模拟不出来这种情况。
期待大侠的清晰解答。

相关帖子

沙发
ayb_ice| | 2012-7-31 08:58 | 只看该作者
总结一点,就是禁止编译器优化

针对第二点:就是每次使用某个变量的值都要重新加载它的值,而不能使用先前备份的值(有时前面已经读出某个变量的值,并且被加载到某个变量中,下次使用时一定要重新从原变量加载)

使用特权

评论回复
板凳
misra|  楼主 | 2012-7-31 09:05 | 只看该作者
总结一点,就是禁止编译器优化

针对第二点:就是每次使用某个变量的值都要重新加载它的值,而不能使用先前备份的值(有时前面已经读出某个变量的值,并且被加载到某个变量中,下次使用时一定要重新从原变量加载) ...
ayb_ice 发表于 2012-7-31 08:58

尽管你的话我理解,用大白话来说,就是编译器 处理有些数据 是放到了寄存器 有些是放固定内存。你的意思是用了volatile就放固定内存。

这个我知道啊。

但是似乎和解释第二点没啥关系。

使用特权

评论回复
地板
ayb_ice| | 2012-7-31 09:41 | 只看该作者
尽管你的话我理解,用大白话来说,就是编译器 处理有些数据 是放到了寄存器 有些是放固定内存。你的意思是用了volatile就放固定内存。

这个我知道啊。

但是似乎和解释第二点没啥关系。 ...
misra 发表于 2012-7-31 09:05


不明白很正常,建议多看看编译的反汇编就明白了

使用特权

评论回复
5
misra|  楼主 | 2012-7-31 09:48 | 只看该作者
我估计至少有95%的搞单片机编程的不明白。请大侠讲讲

使用特权

评论回复
6
ayb_ice| | 2012-7-31 10:05 | 只看该作者
有时候编译器的确很聪明,有时候又自作聪明,
有时自作聪明是错误的,此时用volatile来禁止自作聪明,项目中的中断程序一般都是核心部分,都是精心编写的,很多语句看似无用,其实用处很大,所以一般多用volatile来防止编译器自作聪明

使用特权

评论回复
7
rockli| | 2012-7-31 11:05 | 只看该作者
比如说
char flag = 0;
main()
{
.............
   if(flag == 1)
{
....................
}
}

interrupt()
{
   if(...)
   {   flag = 1; }
}

这段程序看起来没问题,但是编译器可能自作聪明地认为flag == 0, 把主程序中的if部分直接当空气了。

使用特权

评论回复
8
misra|  楼主 | 2012-7-31 12:07 | 只看该作者
比如说
char flag = 0;
main()
{
.............
   if(flag == 1)
{
....................
}
}

interrupt()
{
   if(...)
   {   flag = 1; }
}

这段程序看起来没问题,但是编译器可能自作聪明地认为flag == 0 ...
rockli 发表于 2012-7-31 11:05


大侠的解释 和我在楼主位的解释 “编译器只对main下面的全局变量感兴趣,所以就忽视了中断服务里面的全局变量。”是一样的。

请问 什么编译器   会出现这种情形?

使用特权

评论回复
9
zsyf0918| | 2012-7-31 15:07 | 只看该作者
第二条主要是中断中的计数器等在中断中能改变的数据,尽量用volatile

使用特权

评论回复
10
sinonion| | 2012-7-31 16:10 | 只看该作者
看看我的解释对你有没有帮助:
1.首先楼主认识上有个问题,编译器不仅仅对main里全局变量感兴趣,而是对整个文件/工程的全局变量都感兴趣,所以人们为了避免编译器对某些特殊地址或特殊用途的变量感兴趣,就搞了一些类型修饰,比如volatile,目的是告诉编译器,这些变量你就不用优化了,从而达到对特殊地址的稳定访问。
2.为什么中断里的用到的全局变量要用volatile来修饰呢?原因如下:
  首先:volatile是易变的,不稳定的,它告诉编译器这个变量是不稳定的,它的值由于其他原因会改变的,所以你就不用优化了,每次用到这个变量的时候都需要从内存中取出。
  然后:中断往往是不确定发生的,而中断服务程序里的全局变量在主程序或其他地方会用到,所以它具有了值不确定被改变的可能,所以中断里的全局变量最好还是用volatile来修饰一下!

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
jiabin1024 + 1
11
jiabin1024| | 2012-7-31 17:07 | 只看该作者
LS说的很详细了

使用特权

评论回复
12
yiucing| | 2012-7-31 17:33 | 只看该作者

不加volatile
 
nTest = nTest1;
   if(nTest != nTest1)
   {
    break;
   }

被优化了
是不是这个原因啊

使用特权

评论回复
13
misra|  楼主 | 2012-8-1 09:49 | 只看该作者
你这个例子太复杂  。
我一直认为 应该是7楼的例子  应该就是第二条想要表达的意思。



117563
不加volatile

nTest = nTest1;
   if(nTest != nTest1)
   {
    break;
   }

被优化了
是不是这个原因啊



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




yiucing 发表于 2012-7-31 17:33

使用特权

评论回复
14
misra|  楼主 | 2012-8-1 10:01 | 只看该作者
本帖最后由 misra 于 2012-8-1 12:59 编辑
看看我的解释对你有没有帮助:
1.首先楼主认识上有个问题,编译器不仅仅对main里全局变量感兴趣,而是对整个文件/工程的全局变量都感兴趣,所以人们为了避免编译器对某些特殊地址或特殊用途的变量感兴趣,就搞了一些 ...
sinonion 发表于 2012-7-31 16:10


多谢你的详细解答。不过因为大侠在keilC51下 举不出不用volatile会出现问题的例子,所以属于有理论没实践。
=============================

我现在的认识是这样的:
第二条一个中断服务子程序中会访问到的非自动变量对keilC51是不适用的。也就是说
在 keil C51编译器下 中断服务程序里面用到的变量 不加volatile 不会出现错误,无论任何优化级别。

因为没人能举出例子

使用特权

评论回复
15
ayb_ice| | 2012-8-1 10:48 | 只看该作者
本帖最后由 ayb_ice 于 2012-8-1 11:18 编辑
多谢你的详细解答。不过因为大侠在keilC51下 举不出不用volatile会出现问题的例子,所以属于有理论没实践。
=============================

我现在的认识是这样的:
第二条一个中断服务子程序中会访问到的非自动 ...
misra 发表于 2012-8-1 10:01


典型的自以为是,
下面的例子你怎么看
// main.c
char idata test_volatile;

test_volatile++;



// isr.c
extern const char idata test_volatile;

if(test_volatile == 5){
  ...
}
if(test_volatile == 6){
  ...
}
建议LZ去看一下加与不加volatile的区别

估计你看了也不明白其中的道理

使用特权

评论回复
16
misra|  楼主 | 2012-8-1 11:28 | 只看该作者
本帖最后由 misra 于 2012-8-1 11:29 编辑

帅哥  你这是说的第几条? 中断在哪里?

使用特权

评论回复
17
ayb_ice| | 2012-8-1 11:51 | 只看该作者
帅哥  你这是说的第几条? 中断在哪里?
misra 发表于 2012-8-1 11:28


自己去整吧

使用特权

评论回复
18
yiucing| | 2012-8-1 11:55 | 只看该作者
15# ayb_ice
这个例子试了一下,加不加看汇编代码完全一样啊,求解释。。
我#12楼的例子难道不能解释这个问题么,因为被优化了,所以永远执行不到吧。。

使用特权

评论回复
19
misra|  楼主 | 2012-8-1 13:09 | 只看该作者
15# ayb_ice  
这个例子试了一下,加不加看汇编代码完全一样啊,求解释。。
我#12楼的例子难道不能解释这个问题么,因为被优化了,所以永远执行不到吧。。 ...
yiucing 发表于 2012-8-1 11:55
不加关键字就 产生寄存器代码。

关键是和中断有啥关系呢? 第二条偏要和中断扯上联系?
没看出15楼对程序结果有啥影响  请明示。

使用特权

评论回复
20
yiucing| | 2012-8-1 13:47 | 只看该作者
是不是要在中断中改变变量的值
而中断又指不定在什么位置就产生了
所以才用关键字指明是易变的
其他地方得小心使用呢

使用特权

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

本版积分规则

个人签名: 循序渐进,道自然而至...........

4

主题

276

帖子

2

粉丝