aut*_*tic 8 c volatile c99 language-lawyer c11
我多次被告知volatile
无法优化对对象的访问,但在我看来,C89,C99和C11标准中的这一部分建议不然:
...实际实现不需要评估表达式的一部分,如果它可以推断出它的值未被使用并且不产生所需的副作用(包括由调用函数或访问易失性对象引起的任何副作用).
如果我理解正确,这句话就说明实际的实现可以优化表达式的一部分,只要满足这两个要求:
在我看来,很多人都把"包括"的含义与"排除"的含义混为一谈.
编译器是否可以区分"需要"的副作用和不需要的副作用?如果时间被认为是一个必要的副作用,那么为什么允许编译器优化掉像/ do_nothing();
或类似的空操作int unused_variable = 0;
?
如果编译器能够推断函数什么都不做(例如void do_nothing() { }
),那么编译器是否可能有理由优化对该函数的调用?
如果编译器能够推断出一个volatile
对象没有被映射到任何关键的东西(也许它被映射/dev/null
到形成一个空操作),那么编译器是否也可能有理由来优化那个非关键的副作用远?
如果编译器可以执行优化来消除不必要的代码,例如do_nothing()
在称为"死代码消除"的过程中调用(这是很常见的做法),那么为什么编译器也不能消除对空设备的易失性写入?
据我所知,编译器可以优化对函数或易失性访问的调用,或者由于5.1.2.3p4,编译器也无法优化掉.
我认为"包括任何"适用于"所需的副作用",而你似乎将其视为适用于"表达的一部分".
所以意图是说:
...实际实现不需要评估表达式的一部分,如果它可以推断出它的值没有被使用并且没有产生所需的副作用.
所需副作用的例子包括:
- 由该表达式调用的函数引起的所需副作用
- 访问volatile变量
现在,标准没有定义所需的副作用一词.第4节也没有尝试定义它 - 它正在尝试(并没有很好地成功)提供示例.
我认为唯一明智的解释是将其视为5.1.2.3/6定义的可观察行为.所以写起来要简单得多:
实际实现不需要评估表达式的一部分,如果它可以推断出它的值没有被使用并且不会引起任何可观察的行为.
编辑中的问题由5.1.2.3/6回答,有时也称为as-if规则,我在这里引用:
符合实施的最低要求是:
- 根据抽象机器的规则严格评估对易失性对象的访问.
- 在程序终止时,写入文件的所有数据应与根据抽象语义执行程序的结果相同.
- 交互设备的输入和输出动态应按照7.21.3的规定进行.这些要求的目的是尽快出现无缓冲或行缓冲输出,以确保在程序等待输入之前实际出现提示消息.
这是该程序的可观察行为.
回答编辑中的具体问题:
编译器是否可以区分"需要"的副作用和不需要的副作用?如果时间被认为是必要的副作用,那么为什么允许编译器优化掉do_nothing(); 或int unused_variable = 0;?
时间不是副作用.这里所谓的"需要"副作用可能意味着导致可观察行为的副作用.
如果编译器能够推断函数什么都不做(例如,void do_nothing(){}),那么编译器是否可能有理由优化对该函数的调用?
是的,这些可以优化,因为它们不会导致可观察的行为.
如果编译器能够推断出一个volatile对象没有映射到任何关键的东西(也就是说它可能映射到/ dev/null以形成一个null操作),那么编译器是否也可能有理由优化那个非-crucial副作用吗?
不,因为对volatile对象的访问被定义为可观察行为.
如果编译器可以执行优化以消除不必要的代码,例如在称为"死代码消除"的过程中调用do_nothing()(这是很常见的做法),那么为什么编译器也不能消除对null设备的易失性写入?
因为volatile访问被定义为可观察行为,而空函数则不是.