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 中国大陆许可协议进行许可。

posted @   seekwhale13  阅读(98)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起