问题引出
在嵌入式开发中,对于指向寄存器的指针,前面常常加上修饰符volatile,比如下面的代码:
static volatile unsigned int *CCM_CCGR1;
这个指针指向IMX6ULL的寄存器CCM_CCGR1,前面用了修饰符volatile,下面是详细解读。
volatile关键字概述
在C语言中,关键字 volatile 是一种类型修饰符,表示所修饰的变量可能在程序的控制流之外被修改,通常用于硬件寄存器、信号处理程序或者多线程的共享变量等场景。它告诉编译器不要对该变量的读写操作进行优化。
在上下文中的意义:
在代码中,CCM_CCGR1 是指向硬件寄存器的指针。这些指针指向的寄存器的值可能在程序之外由硬件修改,比如时钟控制或其他外设配置。通过添加 volatile 修饰符,可以确保每次访问该变量时,程序都会重新从寄存器地址读取值,而不是使用编译器可能优化存储的缓存值。
volatile 的关键作用:
-
防止编译器优化:
编译器通常会优化代码,将变量存储在寄存器中而不是每次都访问内存。加了volatile后,编译器不会对该变量进行此类优化,每次都从变量所在的实际地址读取或写入值。 -
确保数据的即时性:
如果变量的值是由外部事件(如硬件、其他线程)改变的,加上volatile后,编译器会确保对该变量的访问始终获取最新的值。 -
典型应用场景:
- 硬件寄存器: 像代码中的
CCM_CCGR1,其值是由硬件控制,可能随时改变。 - 中断处理程序: 中断可能会修改某些全局变量。
- 多线程环境: 多线程间共享的变量可能会被其他线程修改。
- 硬件寄存器: 像代码中的
示例说明:
int value = 0; // 非volatile变量
volatile int flag = 0; // volatile变量
void func(void)
{
while (!flag) // 如果没有volatile,编译器可能优化为死循环
{
// 编译器可能认为flag不会被修改,而优化掉重复读取
}
// 当flag被硬件或其他程序修改后,带volatile的flag能反映最新值
}
在代码中的意义
static volatile unsigned int *CCM_CCGR1;
表示 CCM_CCGR1 是一个指向硬件寄存器的指针,由于硬件寄存器的值可能随时发生变化,使用 volatile 确保每次访问时都读取最新值。
特别注意:volatile的位置不一样,意义也不一样
volatile 修饰的不同位置会对代码的含义产生不同影响:
-
修饰指针指向的内容:
volatile unsigned int *ptr;表示
ptr所指向的地址(寄存器的值)是易变的,每次访问时都会重新读取该地址的值。 -
修饰指针变量:
unsigned int *volatile ptr;表示
ptr这个指针变量本身是易变的,编译器不能优化对ptr本身的访问,每次都要重新读取指针的值。
在这个地方,显然指针所指向的内容是易变的,而指针变量本身不是易变的,所以volatile的位置在前方,所以要用1中的代码。

2836

被折叠的 条评论
为什么被折叠?



