有没有在C标准(我想在这一刻什么C99 + TC1-3 C11)是保证这&并|不会是短路?
如果我写:
x = y & foo();
Run Code Online (Sandbox Code Playgroud)
......我希望foo将永远被调用,但真正定义的?从理论上讲,除非标准的说法,否则,如果y包含0,运行时优化可以跳过的东西由于缺少说是不允许呼叫.(与此同样|,如果左侧操作数已经全部为位,您可以忽略右侧操作数.就此而言,如果是的话,甚至x = y * foo(); 可能会被短路.)y0
不熟悉规范(我不知道),证明这样的负面是很棘手的.我可以对比&(C99中的6.5.10)和&&(C99中的6.5.13)中的部分.在后者中,它非常清楚:
与按位二元
&运算符不同,运算&&符保证从左到右的评估; 在评估第一个操作数后有一个序列点.如果第一个操作数比较等于0,则不计算第二个操作数.
......但6.5.10没有明确说明其负面版本.
我认为6.5.10 没有定义一个序列点意味着foo总是被调用并且没有调用它的实现将是非标准的这一事实似乎是合理的.我是对的吗?
jpa*_*cek 19
我认为6.5.10没有定义一个序列点来表示foo总是被调用而且没有调用它的实现是非标准的,这似乎是合理的.我是对的吗?
是的,不是.实际上,不会调用foo的实现将是非标准的.但是,它与序列点没有任何关系.
这里适用的段落为5.1.2.3/3:
在抽象机器中,所有表达式都由语义指定.实际实现不需要评估表达式的一部分,如果它可以推断出它的值未被使用并且不产生所需的副作用(包括由调用函数或访问易失性对象引起的任何副作用).
R..*_*R.. 14
在这种情况下,序列点与它无关.C标准定义了逻辑机器的行为方式,并要求实现的行为就像它遵循该行为一样; 任何优化对于程序的行为必须是透明的.
在C语言中的唯一运营商,其定义是不要评价(全部)它们的操作数是?:,&&,||,和sizeof.实现可能短路的唯一方法,|或者&是否确定(1)单个操作数的值足以知道结果,或者至少在结果仅被使用时知道结果是零还是非零作为真值,和(2),所述另一个操作数没有副作用,因此不计算它的行为是相同的,就好像它进行评价.
通过函数调用,编译器不太可能确定它没有副作用,除非它是static或者使用像gcc这样的编译器特定属性标记__attribute__((const)).
编辑:从C99,5.1.2.3:
在抽象机器中,所有表达式都按语义指定进行计算.实际实现不需要评估表达式的一部分,如果它可以推断出它的值未被使用并且不产生所需的副作用(包括由调用函数或访问易失性对象引起的任何副作用).
然后,明确记录不评估其操作数的运算符.
如果实现可以确定foo函数调用没有改变程序的可观察的bevahior,则foo不需要评估调用.
(C11,5.1.2.3p4)"在抽象机器中,所有表达式都按语义指定进行评估.实际实现不需要评估表达式的一部分,如果它可以推断出它的值没有被使用而且没有必要的副作用生成(包括通过调用函数或访问volatile对象而导致的任何内容)."
在C11中增加并澄清了可观察行为的概念:
(C11,5.1.2.3p6)"对符合实现的最低要求是: - 严格按照抽象机器的规则评估对易失性对象的访问. - 在程序终止时,写入文件的所有数据应与结果是根据抽象语义执行程序会产生. - 交互设备的输入和输出动态应按照7.21.3的规定进行.这些要求的目的是尽快出现无缓冲或行缓冲输出尽可能确保在程序等待输入之前实际出现提示消息.这是程序的可观察行为."