正在加载···
AI摘要
HunYuan-Lite

在 C 语言里,volatile属于类型修饰符,其主要功能是告知编译器某个变量可能会以不可预知的方式被修改。这些不可预知的修改来源多样,像硬件、中断服务程序或者其他线程都可能进行修改。使用volatile的目的在于防止编译器对该变量的访问实施优化,以此保证每次对变量的读写操作都是直接针对内存进行的,否则编译器可能会把变量的值缓存到寄存器中。

使用场景

  1. 访问硬件寄存器
    在进行嵌入式系统编程时,常常需要对硬件寄存器进行直接访问,而这些寄存器的值可能会因为硬件状态的改变而发生变化。

    1
    2
    3
    4
    5
    // 定义一个指向硬件寄存器的指针
    volatile unsigned int* const UART_STATUS = (volatile unsigned int*)0x40000000;

    // 读取寄存器的值,每次都会直接从内存读取
    unsigned int status = *UART_STATUS;
  2. 在中断服务程序(ISR)中使用全局变量
    当中断发生时,会对全局变量的值进行修改,此时就需要用volatile来确保主程序能够正确感知到这种变化。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    volatile int flag = 0;

    // 中断服务程序
    void ISR(void) {
    flag = 1; // 当中断发生时设置标志
    }

    // 主程序
    int main(void) {
    while (!flag) { // 编译器不会对flag进行优化,每次都会读取最新值
    // 等待中断
    }
    // 处理中断事件
    return 0;
    }
  3. 多线程环境下的共享变量
    在多线程程序中,为了保证变量的可见性,通常会使用volatile。不过要注意,它不能保证原子操作,也不能替代同步机制。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 线程1和线程2共享的变量
    volatile int shared_variable = 0;

    // 线程1:修改共享变量
    void thread1_function(void) {
    shared_variable = 1;
    }

    // 线程2:读取共享变量
    void thread2_function(void) {
    int value = shared_variable; // 确保读取到最新值
    }

volatile和指针

  1. 指针指向的是一个volatile的对象,但是指针变量本身并不是volatile的

    1
    volatile int* ptr;
  2. 指针变量本身是volatile 的,但是指针所指的内容并不是volatile的

    1
    int* volatile ptr;
  3. 指针就本身是个volatile的变量,又指向了volatile的数据内容

    1
    volatile int* volatile ptr;

volatile和结构体

  1. 修饰结构体成员
    当结构体成员被声明为 volatile 时,对该成员的每一次访问都会直接访问内存。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    typedef struct {
    volatile int value;
    } VolatileStruct;

    void example(VolatileStruct* s) {
    s->value = 10; // 直接写入内存
    int a = s->value; // 直接从内存读取
    int b = s->value; // 再次从内存读取,不会使用缓存
    }
  2. 修饰结构体本身
    如果只是将结构体本身声明为 volatile,那么通过该结构体指针访问成员时,所有成员都会被当作 volatile 类型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    typedef struct {
    int x;
    int y;
    } Point;

    volatile Point* pt; // 整个结构体被视为 volatile

    void modify_point(void) {
    pt->x = 10; // 相当于 volatile 访问
    pt->y = 20; // 相当于 volatile 访问
    }