C语言volatile关键字详解
正在加载···
AI摘要
HunYuan-Lite
在 C 语言里,volatile属于类型修饰符,其主要功能是告知编译器某个变量可能会以不可预知的方式被修改。这些不可预知的修改来源多样,像硬件、中断服务程序或者其他线程都可能进行修改。使用volatile的目的在于防止编译器对该变量的访问实施优化,以此保证每次对变量的读写操作都是直接针对内存进行的,否则编译器可能会把变量的值缓存到寄存器中。
使用场景
访问硬件寄存器
在进行嵌入式系统编程时,常常需要对硬件寄存器进行直接访问,而这些寄存器的值可能会因为硬件状态的改变而发生变化。1
2
3
4
5// 定义一个指向硬件寄存器的指针
volatile unsigned int* const UART_STATUS = (volatile unsigned int*)0x40000000;
// 读取寄存器的值,每次都会直接从内存读取
unsigned int status = *UART_STATUS;在中断服务程序(ISR)中使用全局变量
当中断发生时,会对全局变量的值进行修改,此时就需要用volatile来确保主程序能够正确感知到这种变化。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15volatile int flag = 0;
// 中断服务程序
void ISR(void) {
flag = 1; // 当中断发生时设置标志
}
// 主程序
int main(void) {
while (!flag) { // 编译器不会对flag进行优化,每次都会读取最新值
// 等待中断
}
// 处理中断事件
return 0;
}多线程环境下的共享变量
在多线程程序中,为了保证变量的可见性,通常会使用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和指针
指针指向的是一个volatile的对象,但是指针变量本身并不是volatile的
1
volatile int* ptr;
指针变量本身是volatile 的,但是指针所指的内容并不是volatile的
1
int* volatile ptr;
指针就本身是个volatile的变量,又指向了volatile的数据内容
1
volatile int* volatile ptr;
volatile和结构体
修饰结构体成员
当结构体成员被声明为 volatile 时,对该成员的每一次访问都会直接访问内存。1
2
3
4
5
6
7
8
9typedef struct {
volatile int value;
} VolatileStruct;
void example(VolatileStruct* s) {
s->value = 10; // 直接写入内存
int a = s->value; // 直接从内存读取
int b = s->value; // 再次从内存读取,不会使用缓存
}修饰结构体本身
如果只是将结构体本身声明为 volatile,那么通过该结构体指针访问成员时,所有成员都会被当作 volatile 类型。1
2
3
4
5
6
7
8
9
10
11typedef struct {
int x;
int y;
} Point;
volatile Point* pt; // 整个结构体被视为 volatile
void modify_point(void) {
pt->x = 10; // 相当于 volatile 访问
pt->y = 20; // 相当于 volatile 访问
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 xgclevo的博客!
评论