0

0

c++中如何使用volatile关键字_c++防止编译器优化的作用【汇总】

尼克

尼克

发布时间:2026-01-25 08:55:16

|

193人浏览过

|

来源于php中文网

原创

volatile不阻止编译器重排、不保证原子性与线程间可见性,仅禁止对自身读写的合并/删除;适用场景限于内存映射I/O、信号处理中的sig_atomic_t变量及setjmp/longjmp相关变量。

c++中如何使用volatile关键字_c++防止编译器优化的作用【汇总】

volatile 在 C++ 中不阻止编译器优化,它只告诉编译器:这个变量的值可能在任何时刻被外部(非当前线程、硬件、信号处理函数等)修改,因此每次访问都必须从内存重新读取,每次写入都必须立即写回内存——但它不提供原子性、不保证顺序、不解决数据竞争

volatile 不能替代 std::atomic 的典型场景

你写 volatile bool flag = false; 并在信号处理函数里设为 true,主线程轮询它,看似能退出循环。但问题在于:

  • 读写 flag 仍可能被重排(volatile 不带 memory order 语义)
  • 如果 flag 是多字节类型(如 volatile int),硬件层面的读写未必是原子的
  • 在多线程中,volatile 对其他线程的可见性无保证(缺少 cache coherency 同步)

真正该用 std::atomic,配合 .load(std::memory_order_acquire).store(true, std::memory_order_release)

volatile 真正有效的三个地方

它只在以下明确由“非本线程控制的异步修改”场景下有意义:

立即学习C++免费学习笔记(深入)”;

  • 内存映射 I/O 寄存器:比如嵌入式中操作 *((volatile uint32_t*)0x40020000) = 0x1;,防止编译器把两次写合并或删掉
  • 信号处理函数中访问的全局变量:必须声明为 volatile sig_atomic_t(注意:仅 sig_atomic_t 类型才被标准保证可安全异步访问)
  • 与 setjmp/longjmp 配合的局部变量:若该变量在 setjmp 后被 longjmp 跳过其作用域,又在跳转后被访问,需加 volatile 防止被优化掉(C 标准要求,C++ 也沿用)

volatile 和编译器优化的关系

不禁止所有优化,只禁用两类:

图星人
图星人

好用的AI生图工具,百万免费商用图库

下载
  • 禁止将多次读合并为一次(例如循环中反复读 volatile int* p,每次生成 mov eax, [p]
  • 禁止将多次写合并/延迟/删除(例如连续写 *p = 1; *p = 2;,不会被优化成只剩 *p = 2;

但它不限制指令重排,也不影响对非 volatile 变量的优化。下面这段代码依然危险:

volatile bool ready = false;
int data = 42;

// 线程 A: data = 123; // 编译器可能把这个写重排到 ready = true 之后 ready = true; // volatile 写,但不约束 data 的写顺序

// 线程 B: while (!ready) {} // volatile 读,但不保证看到 data == 123 printf("%d", data); // 可能打印 42

这里必须用 std::atomic + acquire/release 才能建立 happens-before。

常见误用和编译器差异

这些写法在实际项目中高频出错:

  • volatile std::shared_ptr —— 无意义,shared_ptr 内部引用计数操作不是原子的,volatile 不起作用
  • volatile 成员函数(void f() volatile)—— 这是 const-correctness 的延伸,表示该函数可被 volatile 对象调用,和内存可见性无关
  • 在 MSVC 中,volatile 曾被扩展为带 acquire/release 语义(已弃用),但 GCC/Clang 从未支持,跨编译器代码绝不能依赖这点

如果你不确定要不要用 volatile,大概率不该用;如果目标是线程同步,一定用 std::atomic 或互斥锁。

相关专题

更多
c语言const用法
c语言const用法

const是关键字,可以用于声明常量、函数参数中的const修饰符、const修饰函数返回值、const修饰指针。详细介绍:1、声明常量,const关键字可用于声明常量,常量的值在程序运行期间不可修改,常量可以是基本数据类型,如整数、浮点数、字符等,也可是自定义的数据类型;2、函数参数中的const修饰符,const关键字可用于函数的参数中,表示该参数在函数内部不可修改等等。

527

2023.09.20

全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

78

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

96

2025.09.18

全局变量怎么定义
全局变量怎么定义

本专题整合了全局变量相关内容,阅读专题下面的文章了解更多详细内容。

78

2025.09.18

python 全局变量
python 全局变量

本专题整合了python中全局变量定义相关教程,阅读专题下面的文章了解更多详细内容。

96

2025.09.18

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

381

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

542

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

53

2025.08.29

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

45

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Java 教程
Java 教程

共578课时 | 50.8万人学习

国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号