编译器能否对volatile变量的自身比较操作做等价优化?
关于volatile变量自比较操作的编译器优化规则
结论
编译器不可以将volatile变量和自身比较的操作直接优化为恒真,必须严格按照代码语义先后两次读取该变量的值,再对两次读取的结果进行比较。
原理说明
- C/C++语言标准对
volatile关键字的核心语义做了明确约束:所有对volatile修饰对象的读、写操作都属于不可被优化消除的可观测副作用,编译器必须严格按照代码编写的次数、顺序执行访问操作,不能假设变量的值在两次访问间隙不会发生变化。 volatile的设计初衷就是适配变量值会被程序主逻辑之外的因素修改的场景:比如变量映射到硬件设备的寄存器、会被中断处理程序异步修改、会被其他CPU核心的线程并发修改等,这类场景下两次读取同一个volatile变量得到不同值是完全合理的预期,a == a的结果完全可能为假,直接优化为恒真会彻底破坏代码的设计逻辑。
实际编译验证
我们可以通过简单的代码测试确认符合标准的编译器的行为,示例代码如下:
volatile int hardware_reg; int check_reg() { // 比较寄存器值是否在两次读取之间发生了变化 return hardware_reg == hardware_reg; }
使用GCC在x86架构下无优化编译得到的汇编代码节选如下:
movl hardware_reg(%rip), %eax # 第一次读取变量值到eax寄存器 cmpl hardware_reg(%rip), %eax # 第二次读取变量值直接与eax比较 sete al # 根据比较结果设置返回值 movzbl %al, %eax ret
可以明确看到编译器没有优化掉任何一次读取操作,严格执行了两次读取后再比较的逻辑。
内容的提问来源于stack exchange,提问作者arye
相关产品推荐
相关产品推荐

