C++和C中的volatile 关键字

在 C/C++ 中volatile 关键字的作用

1.防止编译器优化

编译器在编译程序时,为了提高程序的执行效率,会对代码进行优化。例如,当编译器发现一个变量的值在一段代码中没有被显式地改变时,它可能会将这个变量的值缓存到寄存器中,后续对这个变量的读取操作就直接从寄存器中获取值,而不是从内存中读取。然而,对于一些特殊的变量,如硬件寄存器映射的内存地址或者被多个线程共享的变量,这种优化可能会导致错误的结果。volatile关键字就是告诉编译器,这个变量是 "易变的",不要对它进行这种优化,每次访问这个变量都要从内存中读取,每次修改这个变量也要及时写回内存。

例如,考虑一个简单的程序,它通过内存映射的方式访问硬件寄存器:

在这个例子中,如果没有volatile关键字,编译器可能会认为hardware_register的值在两次读取之间没有改变,从而只进行一次读取并将值缓存起来,这显然不符合访问硬件寄存器的实际情况。

复制代码
#include <stdio.h>

// 假设这是一个硬件寄存器的地址
volatile unsigned int * hardware_register = (volatile unsigned int *)0x12345678;

int main()
 {
    // 读取硬件寄存器的值
    unsigned int value1 = *hardware_register;
    // 做一些其他事情
    //...
    // 再次读取硬件寄存器的值
    unsigned int value2 = *hardware_register;
    // 编译器不会优化掉第二次读取操作,因为hardware_register被声明为volatile
    return 0;
}

2.多线程环境中的可见性

在多线程编程中,volatile关键字可以用于保证变量在不同线程之间的 "可见性"。当一个线程修改了一个volatile变量的值时,其他线程能够立即看到这个修改。不过,需要注意的是,volatile并不能保证线程安全的所有方面,如原子性和顺序一致性。它只是保证了变量的可见性,防止编译器对变量的访问进行不恰当的优化。

例如,假设有两个线程,一个线程用于更新一个变量的值,另一个线程用于读取这个变量的值:

在这个例子中,shared_variable被声明为volatile,这可以帮助确保一个线程对它的修改能被另一个线程看到。但由于++操作不是原子操作,这个程序可能仍然会出现数据不一致的问题。

复制代码
#include <iostream>
#include <thread>
#include <atomic>
using namespace std;
volatile int shared_variable = 0;

void update_variable() {
    for (int i = 0; i < 1000; ++i) {
        shared_variable++;
    }
}

int main()
 {
    thread t1(update_variable);
    thread t2(update_variable);
    t1.join();
    t2.join();
    cout << "shared_variable = " << shared_variable << endl;
    return 0;
}

volatile 关键字与 const 关键字的区别

1.语义不同

const关键字主要用于定义常量。它告诉编译器这个变量的值是不允许被修改的。例如:

复制代码
const int a = 10;
a = 20; // 这是错误的,编译器会报错,因为试图修改一个const变量的值

volatile关键字强调变量是易变的,主要用于告诉编译器不要对变量的访问进行优化,重点在于变量值的不确定性(可能被外部因素改变),而不是限制变量的修改。

2.编译器处理方式不同

对于const变量,编译器会在编译阶段进行检查,确保程序不会对其进行非法的修改操作。并且在很多情况下,编译器会将const变量的值直接替换为常量值,以提高程序的运行效率。

例如下面,编译器可能会直接将c的值计算为10,而不是在运行时去读取b的值。

复制代码
const int b = 5;
int c = b * 2;

对于volatile变量,编译器不会进行上述的优化。每次访问volatile变量时,编译器都会生成从内存中读取变量值的代码,每次修改volatile变量时,也会及时将新的值写回内存。

3.使用场景不同

const通常用于定义那些在程序运行过程中不应该被改变的常量,如数学常数、配置参数等。例如

复制代码
const double PI = 3.1415926;

volatile主要用于与硬件交互、多线程编程等场景中,处理那些可能被外部设备或其他线程改变的变量,如硬件寄存器、共享变量等。

相关推荐
2601_9622186120 分钟前
C++ string 类原理、踩坑与对象语义详解
开发语言·c++
爱写代码的小朋友35 分钟前
Windows 下 MSYS2 + MinGW64 安装与使用 OpenCV 全指南(含踩坑记录)
c++·人工智能·windows·opencv
重生之小比特44 分钟前
【C++进阶】封装红⿊树实现mymap和myset
开发语言·c++
YYYing.1 小时前
【设计模式系列 (四) 】建造者模式
c++·后端·设计模式·建造者模式·c/c++
羑悻的小杀马特1 小时前
Docker高阶实战:从Redis集群到C++微服务,全面解析镜像优化与生产环境部署+镜像制作常见问题详解
c++·redis·docker·镜像制作·dockefile
别动我齐刘海1 小时前
ROS2 Jazzy + C++ 时间系统——Time / Clock / Duration
linux·c++·人工智能·学习·机器学习·机器人·自动驾驶
重生之小比特1 小时前
【C++进阶】unordered_set 和unordered_map 深度解析
c++·哈希算法
芯祥联2 小时前
STM32 上跑 MQTT 怎么选?嵌入式 MQTT 客户端 C 语言实现对比
c语言·stm32·单片机·嵌入式硬件·网络协议·开源·broker
chenbingjie_c9 小时前
C++ 进阶核心知识点总结:模板、内存分区、new/delete、内存池
开发语言·c++
Escalating_xu10 小时前
【C 语言】深入理解指针(1·下):指针运算、野指针、assert 与传址实战
java·c语言·开发语言