volatile int vfoo = 0;
void func()
{
int bar;
do
{
bar = vfoo; // L.7
}while(bar!=1);
return;
}
此代码忙于等待变量变为1
。如果在第一遍vfoo
上未设置为1
,我会卡在里面吗。
此代码编译时没有警告。 标准对此有何说法?
vfoo
被声明为volatile
。因此,应不优化对该变量的读取。volatile
资格。是否允许编译器优化对此bar
的写入?即编译器将对vfoo
进行读取访问,并允许丢弃此值而不将其分配给bar
(在L.7)。答案 0 :(得分:3)
标准对此要说的包括:
5.1.2.3程序执行
¶2访问易失性对象,修改对象,修改文件或调用执行任何这些操作的函数都是副作用,它们是执行环境状态的变化。对表达式的评估通常包括值计算和副作用的启动。左值表达式的值计算包括确定指定对象的身份。
¶4在抽象机中,所有表达式均按语义指定的方式求值。如果实际实现可以推断出未使用表达式的值并且没有产生所需的副作用(包括由调用函数或访问易失性对象引起的副作用),则无需对表达式的一部分进行求值。
¶6对一致性实现的最低要求是:
- 严格根据抽象机的规则评估对易失对象的访问。
- ...
尤其是从¶2中获得的收益应该是,访问易失性对象与调用printf
之类的东西没有什么不同-由于它具有副作用,因此不能忽略它。想象一下,您的程序将bar = vfoo;
替换为bar = printf("hello\n");
答案 1 :(得分:2)
volatile变量必须在任何访问中读取。在您的代码段中,无法优化读取。编译器知道bar
可能会受到副作用的影响。这样就可以正确检查条件了。
答案 2 :(得分:0)
但是,
bar
不具有挥发性。
变量bar
用于保存值。您是否在乎存储在其中的值,还是在乎该变量是否根据ABI精确表示?
易失性将向您保证后者。您的程序取决于前者。
是否允许编译器优化对此栏的写入?
当然。为什么您要可能关心所读取的值是否真的写入了分配给堆栈上变量的内存位置?
您所指定的只是将读取的值作为退出条件进行了测试:
bar = ...
}while(bar!=1);
。即编译器将对vfoo进行读取访问,并允许 丢弃此值,而不将其分配给bar(在L.7)。
当然不是!
编译器需要保留volatile读取所获得的值足够的时间,以便能够将其与1进行比较。但是,您再也不需要了,因为您以后再也不会使用bar
了。
可能是一个奇怪的CPU作为条件寄存器中的EQ1(“等于1”)标志,每当装入等于1的值时就将其置位。这样,编译器甚至不会临时存储读取值,而仅存储EQ1条件测试。
根据您的假设,编译器可以丢弃所有非易失性变量的变量值,非易失性对象几乎没有任何用途。