打印
[学习笔记]

理解C语言中的volatile修饰符

[复制链接]
2209|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
kkzz|  楼主 | 2022-10-24 21:45 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
和 const 不同(关于 const 可以看 const 小节),当一个变量声明为 volatile,说明这个变量会被意想不到的改变。最为典型的就是 I/O 的输入寄存器了,因为这个变量的值和外部电平有关系,一旦外部电平发生了变化,那么这个变量也就跟着变。当然还有其它寄存器也是如此,比如各种状态寄存器、定时计数器等,他们的改变是靠硬件来改变的,你的程序只能读取数据,所以一定要申明为 volatile 才行,这样当你的优化级别提高的时候,你的程序也就能保证不会因为过度优化而出现问题。

那么申明为 volatile 的变量对编译器有什么影响呢?我们知道编译器是有优化功能的,很多时候,有些变量的值在运行过程可能是不变的,如果每次访问这个变量都要从原来的内存获得变量值,那是很浪费时间的,如果你让你的的编译器不做优化,那么它每次访问这个变量都会从内存读出数据,这样不仅效率不高,代码量也会比较大,而一旦进行优化了,编译器就会把它认为不变的量保存在内部寄存器中,每次访问这个变量的时候就访问这个寄存器就可以了,这样运行效率将大大提高。所以一般写代码的时候都会有两个版本,一个是 Debug 版本,一个是 Release 版本。 Debug 版本和 Release 版本其中的一个区别就是优化级别的不同,当然他们的不同不仅仅表现在这两个方面。

首先来看看两个不同优化等级的情况下的代码情况吧:

可以看到效果还是很明显的。

首先是 Code 减少了 24.1%,RO-data 不变,RW-data 减小了 8,这是因为我在程序中申明了两个指针在程序中并没有使用,所以被优化掉了。

就是这两货占用了 8 个字节空间,现在因为优化等级提高,被优化掉了。然后 ZI-data 保持不变。

这样看来,优化效果还是很明显的。但是代码运行会不会出问题,很大程度上就是 volatile 的问题了。

现在看看库函数的 GPIO 结构体声明:

可以看到每个寄存器声明都是 __IO,而 __IO 最终可以看到就是 volatile:

所以每次编译器碰到申明为 volatile 的变量就不敢用寄存器中的备份了,而是从原来的内存中访问数据。

使用特权

评论回复

相关帖子

沙发
lihuami| | 2022-11-1 10:45 | 只看该作者
volatile是关键字,是一种类型修饰符,用它修饰的变量表示可以被某些编译器未知的因素更改

使用特权

评论回复
板凳
ingramward| | 2022-11-1 10:59 | 只看该作者
不使用volatile定义的变量,可能因为编译器优化而出现一些问题

使用特权

评论回复
地板
averyleigh| | 2022-11-1 11:18 | 只看该作者
volatile定义的变量它的值在编译时是会改变的,跟const相反

使用特权

评论回复
5
tabmone| | 2022-11-1 11:48 | 只看该作者
例如一个被系统时钟更新的变量,那么对象应该声明成volatile。

使用特权

评论回复
6
mikewalpole| | 2022-11-1 14:42 | 只看该作者
表明某个变量的值可能在外部被改变

使用特权

评论回复
7
tpgf| | 2022-11-4 11:39 | 只看该作者
volatile是一个类型修饰符,其作用是作为指令关键字,确保本条指令不会因为编译器的优化而省略,且要求每次直接读值。简单来说,就是防止编译器对代码进行优化。

使用特权

评论回复
8
qcliu| | 2022-11-4 12:06 | 只看该作者
经常使用到volatile变量的例子:
(1)并行设备的硬件寄存器(如状态寄存器);
(2)一个中断服务子程序中会访问到的非自动变量;
(3)多线程应用中被几个任务共享的变量;
嵌入式系统程序经常同硬件、中断、RTOS等等打交道,所有这些都要求使用volatile变量。

使用特权

评论回复
9
drer| | 2022-11-4 12:14 | 只看该作者
在C语言中,volatile关键字可以用来提醒编译器它后面所定义的变量随时有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。

使用特权

评论回复
10
coshi| | 2022-11-4 13:38 | 只看该作者
临界区内部,通过互斥锁(mutex)保证只有一个线程可以访问,因此临界区内的变量不需要是volatile的;而在临界区外部,被多个线程访问的变量应为volatile

使用特权

评论回复
11
kxsi| | 2022-11-4 13:46 | 只看该作者
对于内建类型,不应直接用volatile,而应把它包装为结构的成员,就可以保护了volatile的结构对象不被不受控制地访问.

使用特权

评论回复
12
wiba| | 2022-11-4 15:12 | 只看该作者
Volatile意思是“易变的”,应该解释为“直接存取原始内存地址”比较合适。

  “易变”是因为外在因素引起的,像多线程,中断等;

  C语言书籍这样定义volatile关键字:volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,告诉编译器对该变量不做优化,都会直接从变量内存地址中读取数据,从而可以提供对特殊地址的稳定访问。。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。(简洁的说就是:volatile关键词影响编译器编译的结果,用volatile声明的变量表示该变量随时可能发生变化,与该变量有关的运算,不要进行编译优化,以免出错)

使用特权

评论回复
13
wwppd| | 2023-1-5 11:30 | 只看该作者
变量声明可以不被优化掉的。              

使用特权

评论回复
14
jonas222| | 2023-1-5 11:39 | 只看该作者
这个对编译器影响比较大。              

使用特权

评论回复
15
sdlls| | 2023-1-5 14:35 | 只看该作者
volatile还是很关键的。              

使用特权

评论回复
16
elsaflower| | 2023-1-5 15:14 | 只看该作者
很复杂的理解。              

使用特权

评论回复
17
sesefadou| | 2023-1-5 16:43 | 只看该作者
很多的编译器需要对中断的变量添加这个代码。

使用特权

评论回复
18
i1mcu| | 2023-1-5 17:32 | 只看该作者
C语言的很多关键字都难以理解的。

使用特权

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

本版积分规则

317

主题

10907

帖子

13

粉丝