当前的C标准是否禁止短路还有`|`?

当前的C标准是否禁止短路还有`|`?,c,operators,C,Operators,C标准中是否有任何东西(我想目前是这样)可以保证&和|不会短路 如果我写: x = y & foo(); …我希望foo总是会被调用,但这真的被定义了吗?理论上,除非标准另有说明,否则如果y包含0,运行时优化可能会在没有说明不允许的内容的情况下跳过调用。(与|类似,如果左侧操作数的所有位都已打开,则可以忽略右侧操作数。因此,如果y为0,即使x=y*foo();也可能短路) 由于不太了解规范(我也不知道),要证明这样的否定是很棘手的。我可以对比&(C99中的6.5.10)和&(C99中的

C标准中是否有任何东西(我想目前是这样)可以保证
&
|
不会短路

如果我写:

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