C语言变量修饰符`volatile`的含义和需要注意的地方

问题引出

在嵌入式开发中,对于指向寄存器的指针,前面常常加上修饰符volatile,比如下面的代码:

static volatile unsigned int *CCM_CCGR1;

这个指针指向IMX6ULL的寄存器CCM_CCGR1,前面用了修饰符volatile,下面是详细解读。

volatile关键字概述

在C语言中,关键字 volatile 是一种类型修饰符,表示所修饰的变量可能在程序的控制流之外被修改,通常用于硬件寄存器、信号处理程序或者多线程的共享变量等场景。它告诉编译器不要对该变量的读写操作进行优化。

在上下文中的意义:

在代码中,CCM_CCGR1 是指向硬件寄存器的指针。这些指针指向的寄存器的值可能在程序之外由硬件修改,比如时钟控制或其他外设配置。通过添加 volatile 修饰符,可以确保每次访问该变量时,程序都会重新从寄存器地址读取值,而不是使用编译器可能优化存储的缓存值。

volatile 的关键作用:

  1. 防止编译器优化:
    编译器通常会优化代码,将变量存储在寄存器中而不是每次都访问内存。加了 volatile 后,编译器不会对该变量进行此类优化,每次都从变量所在的实际地址读取或写入值。

  2. 确保数据的即时性:
    如果变量的值是由外部事件(如硬件、其他线程)改变的,加上 volatile 后,编译器会确保对该变量的访问始终获取最新的值。

  3. 典型应用场景:

    • 硬件寄存器: 像代码中的 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 修饰的不同位置会对代码的含义产生不同影响:

  1. 修饰指针指向的内容:

    volatile unsigned int *ptr;
    

    表示 ptr 所指向的地址(寄存器的值)是易变的,每次访问时都会重新读取该地址的值。

  2. 修饰指针变量:

    unsigned int *volatile ptr;
    

    表示 ptr 这个指针变量本身是易变的,编译器不能优化对 ptr 本身的访问,每次都要重新读取指针的值。

在这个地方,显然指针所指向的内容是易变的,而指针变量本身不是易变的,所以volatile的位置在前方,所以要用1中的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昊虹AI笔记

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值