C语言中关键字volatile的含义及用法

自己在学习单片机时,经常会遇到volatile这个关键字,比如在stm32f4xxHAL库的内核源码中

#define     __O     volatile             /*!< Defines 'write only' permissions */
#define     __IO    volatile             /*!< Defines 'read / write' permissions */

每次查了明白了,过后又忘记了,因此写篇博客记录一下。

一、首先volatile的意思是“易变的,不稳定的”,目的是防止编译器优化,防止编译器优化什么意思呢?

1.首先我们先来理解什么是编译器优化

 我们编写C语言程序然后用编译器进行编译时,编译器会对我们所写的程序中的变量和代码进行一定的优化,用下面例子进行阐述

int main()

{

        int  valu_1,valu_2,valu_3;

        valu_1 = 10;

        valu_2 = valu_1;

        valu_3 = valu_2;

        return 0;

}

上面程序运行的顺序为:

第一步:先把10放到valu_1所指向的空间(地址)中,

第二步:将valu_1所指向的空间中的数据读出来,然后再将读出的数据放到valu_2所指向的                空间中;

第三步:将valu_2所指向的空间中的数据读出来,然后再将读出的数据放到valu_3所指向的                空间中;

然而经过编译器编译优化之后就变成将

int main()

{

        int  valu_1,valu_2,valu_3;

        valu_3 = 10;

        return 0;

}

上例有三个变量valu_1,valu_2和valu_3,但是其实是三个相同的变量,并且其它地方并未区分它们三个(所以它们是重复的,可称为“复写”),编译器会用一个变量替换两个或多个相同的变量,将valu_3“传播”给valu_1和valu_2,只剩下一个变量valu_3,当然,反过来优化后只剩下一个valu_1或valu_2也是可以的。

上面不好理解的话可以按照下面理解,编译器优化后变为

int main()

{

        int  valu_1,valu_2,valu_3;

        valu_1 = 10;

        valu_2 = 10;

        valu_3 = 10;

        return 0;

}

上例程序在正常运行的时候确实是好事,但是总会有一些特殊的情况发生,比如,一个中断程序突然改变了valu_1的值为5,那么可能会发生这样的情况:本来valu_1、valu_2和valu_3应该是valu_1改变以后的值5,可是因为编译器在编译时优化valu_1,valu_2,valu_3都是10,因此即使在别的地方被改变成5,但在主函数中使用valu_1、valu_2和valu_3时,其值还是10而不是5,这样程序就会跑出来我们意想不到的结果。

对于编译器的优化想要深入了解的话,可以参考编译器常用的8种优化方法 - 知乎 (zhihu.com)

二、那么volitale“易变的,不稳定的”应该要怎么理解呢?

volatile 是提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都要直接从变量地址中读取数据

对于上述一里面的例子

int main()

{

        int  valu_1,valu_2,valu_3;

        valu_1 = 10;

        valu_2 = valu_1;

        valu_3 = valu_2;

        return 0;

}

如果改为

int main()

{

        volatile int  valu_1,valu_2,valu_3;

        valu_1 = 10;

        valu_2 = valu_1;

        valu_3 = valu_2;

        return 0;

}

再次经过编译之后,因为volatile关键字的作用,编译器不会再对valu_1、valu_2、valu_3进行优化,程序中在任何地方改变了valu_1的值之后,再在主函数中读取valu_1的值的时候,都会从valu_1变量所指向的空间地址中进行读取数据。这样就避免了编译器因为优化暂时从寄存器中取值,避免了valu_1这个变量由别的地方(中断、程序、线程等等)更新成5了,但是在主函数中还是10的现象。

总结:

volatile 关键字是一种类型修饰符,用它声明的类型变量表示可以被某些编译器未知的因素更改。volatile 提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如 果没有 volatile 关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。所以遇到这个关键字声明的变量,编译器对访问该变量的代码就不再进行优化,从而可以提供对特殊地址的稳定访问

可是如果你大量使用volatile的话,没有优化,就会降低程序运行的效率。

本来C语言的运行效率就比汇编低了不少,所以说volatile在加的时候要尽量考虑好,因为很多程序运行的时候特别注重效率,需根据实际编程需要,合理使用。

以上是我对volatile关键字的理解,可能有理解不恰当或不对之处,希望进行指正。

C语言是一种广泛应用于系统软件和应用程序开发的编程语言。它有包括32个关键字在内的一些固定的标识符,这些关键字在编程有着特殊的含义用法。 下面是这些关键字含义用法的简要介绍: 1. auto:该关键字用于定义自动变量,它在函数内部声明的变量默认为自动变量。 2. break:用于断循环或开关语句的执行。 3. case:用于定义开关语句的某个具体情况。 4. char:用于声明字符变量。 5. const:用于定义常量,其值不能被修改。 6. continue:用于跳过循环剩余的语句,继续执行下一次迭代。 7. default:定义开关语句的默认情况。 8. do:开始一个do-while循环。 9. double:声明双精度浮点数变量。 10. else:用于在条件不满足时执行的分支。 11. enum:用于定义一个枚举类型。 12. extern:用于声明外部变量或函数。 13. float:声明浮点数变量。 14. for:开始一个for循环。 15. goto:用于无条件跳转到代码的标记处。 16. if:用于条件判断,执行分支。 17. int:声明整数变量。 18. long:声明长整数变量。 19. register:用于声明寄存器变量。 20. return:用于从函数返回一个值。 21. short:声明短整数变量。 22. signed:声明有符号整数类型。 23. sizeof:返回变量或数据类型的大小。 24. static:用于定义静态变量或函数。 25. struct:用于定义结构体类型。 26. switch:开始一个开关语句。 27. typedef:用于定义新的数据类型。 28. union:用于定义联合类型。 29. unsigned:声明无符号整数类型。 30. void:用于声明无返回值的函数或空指针。 31. volatile:用于声明易变的变量。 32. while:开始一个while循环。 这些关键字的理解和正确使用对于编写高效、可读性强的C语言代码至关重要。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值