当前的C标准是否禁止短路还有`|`?
C标准中是否有任何东西(我想目前是这样)可以保证当前的C标准是否禁止短路还有`|`?,c,operators,C,Operators,C标准中是否有任何东西(我想目前是这样)可以保证&和|不会短路 如果我写: x = y & foo(); …我希望foo总是会被调用,但这真的被定义了吗?理论上,除非标准另有说明,否则如果y包含0,运行时优化可能会在没有说明不允许的内容的情况下跳过调用。(与|类似,如果左侧操作数的所有位都已打开,则可以忽略右侧操作数。因此,如果y为0,即使x=y*foo();也可能短路) 由于不太了解规范(我也不知道),要证明这样的否定是很棘手的。我可以对比&(C99中的6.5.10)和&(C99中的
&
和|
不会短路
如果我写:
x = y & foo();
…我希望foo
总是会被调用,但这真的被定义了吗?理论上,除非标准另有说明,否则如果y
包含0
,运行时优化可能会在没有说明不允许的内容的情况下跳过调用。(与|
类似,如果左侧操作数的所有位都已打开,则可以忽略右侧操作数。因此,如果y
为0
,即使x=y*foo();
也可能短路)
由于不太了解规范(我也不知道),要证明这样的否定是很棘手的。我可以对比&
(C99中的6.5.10)和&
(C99中的6.5.13)中的章节。在后者中,非常清楚:
与按位二进制&
运算符不同,&
运算符保证从左到右求值;第一个操作数求值后有一个序列点。如果第一个操作数比较等于0
,则不计算第二个操作数
…但6.5.10没有明确说明其负面版本
在我看来,6.5.10没有定义序列点这一事实似乎是合理的,这意味着
foo
总是会被调用,而没有调用它的实现将是非标准的。我说的对吗?在这种情况下,序列点与此无关。C标准定义了逻辑机器的行为方式,并要求实现的行为如同遵循该行为一样;任何优化都必须对程序的行为透明
C语言中唯一定义为不计算(所有)操作数的运算符是?:
,&&
,|
,和sizeof
。实现短路|
或&
的唯一方法是确定(1)单个操作数的值足以知道结果,或者至少在结果仅用作真值时知道结果是零还是非零,以及(2)另一个操作数没有副作用,因此,不评估它的行为与评估它的行为相同
对于函数调用,编译器不太可能确定它没有副作用,除非它是静态的
,或者标记了编译器特定的属性,如gcc的\uuuuu属性((const))
编辑:来自C99,5.1.2.3:
在抽象机器中,所有表达式都按照语义指定的方式进行计算。如果实际实现可以推断表达式的值没有被使用,并且没有产生所需的副作用(包括调用函数或访问易失性对象引起的副作用),则不需要计算表达式的一部分
然后,不计算其操作数的运算符被显式记录为这样的运算符
在我看来,6.5.10没有定义一个序列点这一事实似乎是合理的,这意味着foo总是会被调用,而没有调用它的实现将是非标准的。我说的对吗
是和否。事实上,不调用foo的实现将是非标准的。但是,它与序列点没有任何关系
此处适用的段落为5.1.2.3/3:
在抽象机器中,所有表达式都按照语义的规定进行计算。一
如果可以推断表达式的
未使用该值,且未产生所需的副作用(包括由
调用函数或访问易失性对象)
如果实现可以确定
foo
函数调用不会改变程序的可观察边界,则不需要对foo
调用进行评估
(C11,5.1.2.3p4)“在抽象机器中,所有表达式都按照语义的规定进行求值。如果实际实现能够推断出表达式的值没有被使用,并且没有产生所需的副作用(包括调用函数或访问易失性对象引起的副作用),则不需要对表达式的一部分求值。”
C11中增加并阐明了可观察行为的概念:
(C11,5.1.2.3p6)“一致性实施的最低要求为:
-对易失性对象的访问严格按照抽象规则进行评估
机器。
-程序终止时,写入文件的所有数据应与
根据抽象语义执行程序会产生错误。
-交互设备的输入和输出动态应按照
7.21.3.这些要求的目的是无缓冲或线路缓冲输出
尽快显示,以确保提示消息在
等待输入的程序。
这是程序的可观察行为。”
§6.5.10按位AND运算符
语义
3通常的算术转换是在操作数上执行的
给你。应用通常的算术转换需要计算两个操作数。请注意,这一段没有出现在
&&
、|
或?:
的语义描述中,仅供参考,当前的标准是C11,该网站尚未更新:@SheaLevy:谢谢,我错过了“C11”最终成为现实的机会+1我从未想过按位运算会短路。&&
和|
都是特例<代码>&a