非适当场景禁用 volatile 关键字
6.2.10 ID_forbidVolatile
应在适当的场景中合理使用 volatile 关键字,否则会导致优化或同步相关的多种问题。
在下列场景中可使用 volatile 关键字:
- 对象读写对应外设 IO
- 与信号等中断处理过程共享对象
- 局部对象在 setjmp、longjmp 之间被修改
- 出于安全目的清理内存中的数据
- 在 C/C++ 之外,通过与编译优化不兼容的方式访问对象
在这些场景中,如果相关对象没有用 volatile 关键字限定会导致程序和预期不符,volatile 关键字可以保证对象具有稳定的内存地址,任何读取或写入都可以来源于或作用于内存中的实际数据。
除此之外不应使用 volatile 关键字,不参与过程间跳转的局部 volatile 对象往往意味着 volatile 关键字的滥用。
示例:
volatile int foo(); // Non-compliant
int bar(volatile int x); // Non-compliant
int baz() {
volatile int i = 0; // Non-compliant
return i;
}
例中用于限定返回值对象、参数对象和局部对象的 volatile 关键字是没有实际意义的。
而且要注意 volatile 关键字和 C/C++ 的并发或同步机制没有直接关系,也无法保证相关操作的原子性,如:
volatile int x; // ‘volatile’ is nothing to do with synchronization
void thd() {
LockGuard g;
read_and_write(x); // The ‘volatile’ on ‘x’ is abused
}
例中 x 是不涉及外设的共享对象,thd 是线程函数,LockGuard 是某种 RAII 锁,在已落实同步机制的情况下,不应再使用 volatile 关键字。
依据
ISO/IEC 9899:1999 6.7.3(6)
ISO/IEC 9899:2011 6.7.3(7)
ISO/IEC 14882:2003 7.1.5.1(8)
ISO/IEC 14882:2011 7.1.6.1(7)