OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 5460|回复: 23

求助一下C语言中的volatile作用

[复制链接]

4

主题

8

帖子

0

精华

初级会员

Rank: 2

积分
96
金钱
96
注册时间
2018-7-20
在线时间
15 小时
发表于 2018-8-9 22:55:54 | 显示全部楼层 |阅读模式
3金钱
我发现stm32f10x.h文件里进行了宏定义#define     __O     volatile                  /*!< defines 'write only' permissions     */#define     __IO    volatile                  /*!< defines 'read / write' permissions   */
但是通过网上查询对volatile没有太明白,想请问一下各位有没有什么简单的理解方式,我不要求太深入、太专业,只要能让我这个新人简单明白大概的作用即可,能举出例子更好。
非常感谢各位的教导!


最佳答案

查看完整内容[请看2#楼]

简单地说,volatile就是告诉编译器,不要自作聪明地去优化与这个变量有关的代码 严格做到:每一次的读写都去访问这个变量所在的地址,不要为了省事(提高效率)而直接用CPU自带的寄存器 比如说: volatile int i; i=10; ...... int j=i; 编译生成代码时,CPU一般是用寄存器来进行操作的,用一个寄存器比如R0=10,然后把R0的值赋予变量i, 编译后面int j=i;这一句时,因为中间没有对i进行改变的操作, 编译器想,我何必费 ...
感谢给我帮助的前辈,防止影响论坛版面就不回复了,感谢指点!
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

31

主题

1955

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4524
金钱
4524
注册时间
2018-5-11
在线时间
947 小时
发表于 2018-8-9 22:55:55 | 显示全部楼层
本帖最后由 warship 于 2018-8-9 23:44 编辑

简单地说,volatile就是告诉编译器,不要自作聪明地去优化与这个变量有关的代码
严格做到:每一次的读写都去访问这个变量所在的地址,不要为了省事(提高效率)而直接用CPU自带的寄存器
比如说:
volatile int i;
i=10;
......
int j=i;
编译生成代码时,CPU一般是用寄存器来进行操作的,用一个寄存器比如R0=10,然后把R0的值赋予变量i,
编译后面int j=i;这一句时,因为中间没有对i进行改变的操作,
编译器想,我何必费劲去取i的值呢,我R0不就有现成的i值吗,让j=R0不就行了吗?
正常情况下这是没有问题的,但我们的系统是与硬件相关(或者多任务、中断之类)的,很可能 i 的值通过其它方式(从静态代码中看不出来)中途会改变的,
比如已经变成了20,这时候经过编译器自作主张优化出来的代码,却没有去读这个20,而是让j=R0即=10,得到了错误的结果。
如果我们的程序中,确实有这种某个变量中途会改变的情况,要想不出现上面的错误,就需要声明volatile int i;
告诉编译器,碰到i这个变量,都必须老老实实地到实际地址去取当前值,不要使用R0之类的存货。
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复

使用道具 举报

8

主题

569

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2363
金钱
2363
注册时间
2015-5-8
在线时间
320 小时
发表于 2018-8-10 00:14:59 | 显示全部楼层
关于这种关键字的学习可以看看C语言深度剖析,基本都有
回复

使用道具 举报

160

主题

967

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2097
金钱
2097
注册时间
2014-3-7
在线时间
491 小时
发表于 2018-8-10 08:22:33 | 显示全部楼层
warship 发表于 2018-8-9 22:55
简单地说,volatile就是告诉编译器,不要自作聪明地去优化与这个变量有关的代码
严格做到:每一次的读写都 ...

编译器一级优化应该不会优化到这个层次吧?
回复

使用道具 举报

31

主题

1955

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4524
金钱
4524
注册时间
2018-5-11
在线时间
947 小时
发表于 2018-8-10 08:26:42 | 显示全部楼层
本帖最后由 warship 于 2018-8-10 10:59 编辑
ssssssssssss 发表于 2018-8-10 08:22
编译器一级优化应该不会优化到这个层次吧?

这种是编译器最基本的优化功能,基本属于傻瓜级别的。
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复

使用道具 举报

160

主题

967

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2097
金钱
2097
注册时间
2014-3-7
在线时间
491 小时
发表于 2018-8-10 08:30:21 | 显示全部楼层
本帖最后由 ssssssssssss 于 2018-8-10 08:45 编辑
warship 发表于 2018-8-10 08:26
这种是编译器最基本的优先功能,基本属于傻瓜级别的。

也就是说优化等级为0,也会出现这种优化吗

0级优化:
1、 常数折叠:只要有可能,编译器就执行将表达式化为常数数字的计算,其中包括运行地址的计算。
2、 简单访问优化:对8051系统的内部数据和位地址进行访问优化。
3、 跳转优化:编译器总是将跳转延至最终目标上,因此跳转到跳转之间的命令被删除。
1级优化:
1、 死码消除:无用的代码段被消除。
2、 跳转否决:根据一个测试回溯,条件跳转被仔细检查,以决定是否能够简化或删除。


回复

使用道具 举报

8

主题

89

帖子

0

精华

高级会员

Rank: 4

积分
686
金钱
686
注册时间
2017-8-8
在线时间
494 小时
发表于 2018-8-10 08:57:24 | 显示全部楼层
硬件寄存器、多线程的共享变量等
回复

使用道具 举报

31

主题

1955

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4524
金钱
4524
注册时间
2018-5-11
在线时间
947 小时
发表于 2018-8-10 09:05:05 | 显示全部楼层
ssssssssssss 发表于 2018-8-10 08:30
也就是说优化等级为0,也会出现这种优化吗

0级优化:

这种优化是很基本的,
你先要明白,我们虽然只是简单的给某变量赋值,
生成汇编代码时往往都需要通用寄存器作为中介的。
i=10汇编后的代码写成C语言相当于:R0=10; R1=i的地址; 然后STR R0,(R1)
就是这么费劲的,然后你马上又来一句j=i;  它会傻到再去取i的值吗? 直接就用R0中现存的值了。
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复

使用道具 举报

160

主题

967

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2097
金钱
2097
注册时间
2014-3-7
在线时间
491 小时
发表于 2018-8-10 09:14:42 | 显示全部楼层
本帖最后由 ssssssssssss 于 2018-8-10 09:16 编辑
warship 发表于 2018-8-10 09:05
这种优化是很基本的,
你先要明白,我们虽然只是简单的给某变量赋值,
生成汇编代码时往往都需要通用寄 ...


比如说一个变量count值(不加volatile),执行下面的函数  count=1; count=3;count=GPIO_IDR;count=6;5ms定时器中断里面我让count++;(假设GPIO_IDR值是0x09),定时器跑完一次定时器中断的时候count变量可能是多少?
回复

使用道具 举报

20

主题

227

帖子

0

精华

高级会员

Rank: 4

积分
605
金钱
605
注册时间
2017-7-14
在线时间
116 小时
发表于 2018-8-10 09:15:20 | 显示全部楼层
本帖最后由 SimpleLife 于 2018-8-10 09:17 编辑

volatile作用:无论何时,编译器读取变量都从地址上读取。
情况:在某些编译器下,编译器优化读取方式,若某段时间内程序没有对变量进行改变,编译器读取的值为上次的值。
例子:
PA5,在某段时间内,程序没有对PA5进行设置,在下次读取时,编译器会自动把上个值直接读取出来,
如果PA5是输入口,电平改变了,编译器是不知道的,读取的只能为上次读取的值,
这个时候volatile的作用提现出来了:无论何时,读取变量都从地址上读,这样保证了读取到的值是实时的,准确的。
回复

使用道具 举报

160

主题

967

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2097
金钱
2097
注册时间
2014-3-7
在线时间
491 小时
发表于 2018-8-10 09:17:23 | 显示全部楼层
SimpleLife 发表于 2018-8-10 09:15
在某些编译器下,编译器优化读取方式,例如:PA5,在某段时间内,程序没有进行设置,在下次读取时,编译器 ...

看9楼的帖子
回复

使用道具 举报

20

主题

227

帖子

0

精华

高级会员

Rank: 4

积分
605
金钱
605
注册时间
2017-7-14
在线时间
116 小时
发表于 2018-8-10 09:19:02 | 显示全部楼层
百度上也有很多说明啦
回复

使用道具 举报

31

主题

1955

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4524
金钱
4524
注册时间
2018-5-11
在线时间
947 小时
发表于 2018-8-10 09:24:33 | 显示全部楼层
ssssssssssss 发表于 2018-8-10 09:14
比如说一个变量count值(不加volatile),执行下面的函数  count=1; count=3;count=GPIO_IDR;count= ...

这种赋值语句不说明问题,
我认为编译出来,会以最后一次为准,
即count=6
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复

使用道具 举报

160

主题

967

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2097
金钱
2097
注册时间
2014-3-7
在线时间
491 小时
发表于 2018-8-10 09:28:18 | 显示全部楼层
warship 发表于 2018-8-10 09:24
这种赋值语句不说明问题,
我认为编译出来,会以最后一次为准,
即count=6

如果第一句和第二句加一句i=0;编译器也给我优化了?编译器也给我吧count优化了?
回复

使用道具 举报

160

主题

967

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2097
金钱
2097
注册时间
2014-3-7
在线时间
491 小时
发表于 2018-8-10 09:31:14 | 显示全部楼层
warship 发表于 2018-8-10 09:24
这种赋值语句不说明问题,
我认为编译出来,会以最后一次为准,
即count=6

怎么才能查看编译器优化了的东西?
回复

使用道具 举报

31

主题

1955

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4524
金钱
4524
注册时间
2018-5-11
在线时间
947 小时
发表于 2018-8-10 09:41:26 | 显示全部楼层
ssssssssssss 发表于 2018-8-10 09:28
如果第一句和第二句加一句i=0;编译器也给我优化了?编译器也给我吧count优化了?

赋值的操作是写,写操作基本不会优化的。
容易出问题的主要是读。
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复

使用道具 举报

31

主题

1955

帖子

3

精华

论坛元老

Rank: 8Rank: 8

积分
4524
金钱
4524
注册时间
2018-5-11
在线时间
947 小时
发表于 2018-8-10 09:42:02 | 显示全部楼层
ssssssssssss 发表于 2018-8-10 09:31
怎么才能查看编译器优化了的东西?

仿真的时候对照查看汇编窗口
我的开源链接 https://github.com/ShuifaHe/STM32.git  请关注,点赞支持哦。
回复

使用道具 举报

15

主题

866

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
7603
金钱
7603
注册时间
2016-11-30
在线时间
645 小时
发表于 2018-8-10 09:49:34 | 显示全部楼层
warship 发表于 2018-8-9 22:55
简单地说,volatile就是告诉编译器,不要自作聪明地去优化与这个变量有关的代码
严格做到:每一次的读写都 ...

很易懂!赞一个
回复

使用道具 举报

57

主题

1680

帖子

3

精华

资深版主

Rank: 8Rank: 8

积分
4307
金钱
4307
注册时间
2018-6-30
在线时间
808 小时
发表于 2018-8-10 10:09:23 | 显示全部楼层
warship 发表于 2018-8-9 22:55
简单地说,volatile就是告诉编译器,不要自作聪明地去优化与这个变量有关的代码
严格做到:每一次的读写都 ...

讲得不错,赞一个
业精于勤荒于嬉;行成于思毁于随!
回复

使用道具 举报

4

主题

8

帖子

0

精华

初级会员

Rank: 2

积分
96
金钱
96
注册时间
2018-7-20
在线时间
15 小时
 楼主| 发表于 2018-8-10 15:54:04 | 显示全部楼层
warship 发表于 2018-8-9 22:55
简单地说,volatile就是告诉编译器,不要自作聪明地去优化与这个变量有关的代码
严格做到:每一次的读写都 ...

非常感谢
感谢给我帮助的前辈,防止影响论坛版面就不回复了,感谢指点!
回复

使用道具 举报

8

主题

571

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
2922
金钱
2922
注册时间
2016-5-13
在线时间
185 小时
发表于 2018-8-10 16:18:45 | 显示全部楼层
虽然不明白你们在说什么,但感觉很厉害的样子。
虽然不明白你们在说什么,但感觉很厉害的样子。
回复

使用道具 举报

1

主题

33

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
207
金钱
207
注册时间
2018-4-29
在线时间
48 小时
发表于 2018-8-10 16:49:07 | 显示全部楼层
warship 发表于 2018-8-9 22:55
简单地说,volatile就是告诉编译器,不要自作聪明地去优化与这个变量有关的代码
严格做到:每一次的读写都 ...

感谢我大哥!
回复

使用道具 举报

15

主题

58

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
231
金钱
231
注册时间
2017-7-18
在线时间
83 小时
发表于 2018-11-1 11:06:11 | 显示全部楼层
麻烦一下大家,
我注意到有的处理器包含cache,volatile这样还有效吗?如何保证数据多个备份的一致性呢?
回复

使用道具 举报

0

主题

91

帖子

0

精华

初级会员

Rank: 2

积分
177
金钱
177
注册时间
2018-9-27
在线时间
15 小时
发表于 2018-11-1 11:12:23 | 显示全部楼层
谢谢各位指导,谢谢了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-7-6 02:29

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表