C语言Const、volatile等关键字的使用
参考知乎文章【嵌入式中C语言volatile和const的作用】https://zhuanlan.zhihu.com/p/27484194
常常与硬件打交道的嵌入式C语言编程中,由于其硬件特性,某些变量的值不仅仅在软件中改变,由于硬件的状态也会使其发生变化,如某个状态寄存器。
1.latile关键字的意义:
volatile本意:不稳定的;易发散的;易变的,无定性的。
在嵌入式环境中用volatile关键字声明的变量,在每次对其值进行引用的时候都会从原始地址取值,而不会将值保存在栈或其他位置。也是在告诉编译器,针对该值不要做优化。例如:
1.1某个寄存器值做一次翻转,LED亮灭:
uint8_t *addr =...; //寄存器地址 *addr = 1; //第一个指令,寄存器值置高 *addr = 0; //第二个指令,寄存器值置低
我们设想对它做一次翻转,但编译器可能会对它优化成这样:
uint8_t *addr =...; //寄存器地址 *addr = 0; //第二个指令,寄存器值置低
这里的第一个指令被优化掉了,没有达成我们想要的目标。
正确做法是加上volatile关键字,对于IO寄存器都应该加上volatile
volatile uint8_t *addr =...; //寄存器地址 *addr = 1; //第一个指令,寄存器值置高 *addr = 0; //第二个指令,寄存器值置低
1.2变量值可能在程序外发生改变,用volatile定义的变量会在程序外被改变,每次都必须从内存中读取,而不能重复使用放在寄存器或栈中的备份。
volatile uint8_t flag; flag=0; while(!flag){ doSomeThing(); } doSomeThingElse();
如果没有volatile修饰flag,可能由于编译器优化,一直在while循环中, doSomeThingElse()不会被执行(即使flag的值在其他中断中被更改)。若如上使用了volatile,则会每次都会从原始地址取值,这样当原始地址的值更改后则while能中止并继续执行下方代码。且多任务环境下各任务间共享的标志也应该加volatile。
1.3存储器映射的硬件寄存器通常也要加voliate,因为每次对它的读写都可能有不同意义。
int *uartSendRegist= (unsigned int *)0xXXXXXXXXX;//定义一个串口数据寄存器地址; int init(void) { int i; for(i=0;i< 10;i++) { delaySomeTime(); *uartSendRegist= data[i]; } }
2.Const关键字
const本意位常量,
2.1 编译器一般不为const变量分配内存,而是将它保存在ROM中中,这使得它成为一个编译期间的值,没有了存储与读内存的操作。
2.2 const在编译期保证在C的“源代码”里面,没有对其修饰的变量进行修改的地方(如有则报错,编译不通过),而运行期该变量的值是否被改变则不受const的限制。
3.同时修饰一个变量
表示一个变量在程序编译期不能被修改且不能被优化;在程序运行期,变量值可修改,但每次用到该变量的值都要从内存中读取,以防止意外错误。
#include <stdio.h> const volatile int a = 10; int main(void){ // a = 100; // 非法 int* aPtr = &a; *aPtr = 100; printf("%d,%d",a,*aPtr); }
本文作者:seekwhale13
本文链接:https://www.cnblogs.com/seekwhale13/p/17182900.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步