本问题已经有最佳答案,请猛点这里访问。
#include
int main(void) {
int a = 0, b = 0, c = 0;
++a || ++b && ++c;
printf("%d %d %d", a, b, c);
return 0;
}
gcc 8.1.0的输出为1,0,0。 &&的优先级应高于||。
为什么b和c仍然是0?
由于短路。
表达式++a || ++b && ++c分组为++a || (++b && ++c)。但是,仅当++a是0时才评估||的右侧,但不是。
括号中的表达式不是应该在" ||"之前计算吗?
@EricShi绝对不是。 首先评估||的左侧。
@EricShi您将优先顺序与评估顺序混淆了...
@EugeneSh。 当场,非常重要。
@EricShi,应在||之前求值,但++a不是||,它是该操作数。
这里有三个问题:
优先顺序。
评估顺序。
逻辑运算符短路。
优先顺序意味着++a || ++b && ++c被评估为++a || (++b && ++c)。
但是,由于逻辑运算符的短路要求,因此首先评估++a。只有将其评估为false时,才会评估(++b && ++c)。在您的情况下,++a评估为true。因此,永远不会评估(++b && ++c)。
逻辑或运算符||(以及逻辑与运算符&&)是执行短循环操作的少数运算符之一。
C标准的6.5.14节对逻辑OR运算符进行了以下说明:
4 Unlike the bitwise | operator, the || operator guarantees
left-to-right evaluation; if the second operand is evaluated, there is
a sequence point between the evaluations of the first and second
operands. If the first operand compares unequal to 0, the second
operand is not evaluated.
因为++a的值为1,所以保证||运算符的结果为1,并且不对右侧进行求值。另外,由于&&的优先级高于||,所以||运算符的右侧为++b && ++c,这意味着不会评估++b或++c。
优先级仅控制表达式的解析方式,而不控制表达式的计算方式。算术*的优先级高于+,因此a * b + c被解析为(a * b) + c。但是,可以按任何顺序评估a,b和c中的每一个。必须先知道a * b的结果,然后才能将其添加到c的结果中,但这并不意味着a * b必须在c之前进行求值。
其次,与C中的大多数运算符不同,||和&&运算符强制执行从左到右的求值。像a || b && c这样的表达式将被解析为a || (b && c),但是a始终会首先被求值,并且b && c仅在a的结果为0时才被求值。
就优先级而言,x || y && z的作用与x + y * z相同:第二个运算符的绑定比第一个更紧密,并且这些表达式分别等效于x || (y && z)和x + (y * z)。
问题中的b和c不增加的原因是,除优先级外,逻辑运算还短路:一旦您足够了解结果,其余表达式将被跳过。 ||和&&都从左到右评估其参数,因此在a() || b()和a() && b()中,对a()的调用发生在对b()的调用之前。
在简单的情况下,如果a()返回true,则在表达式a() || b()中将不会执行对b()的调用,因为它不会影响结果。同样,如果a()返回false,则在表达式a() && b()中,将不执行对b()的调用。
在示例代码中,将不执行对b和c的递增操作,因为++a会生成非零值,因此表达式的结果为true,而无需在之后进行任何运算++a。
运算符优先级与求值顺序无关。优先级是将不同类型的运算符及其操作数进行分组的优先级。
所以,表达
++a || ++b && ++c;
将被评估为
++a || (++b && ++c);
逻辑与和逻辑或运算符构成序列点,因此保证了从左到右对其操作数的特定求值顺序。
评估顺序:
Ordering
......
If a sequence point is present between the subexpressions E1 and E2,
then both value computation and side effects of E1 are
sequenced-before every value computation and side effect of E2
Rules
.....
2) There is a sequence point after evaluation of the first (left) operand and before evaluation of the second (right) operand of the following binary operators: && (logical AND), || (logical OR), and , (comma).
逻辑或运算(expr1 || expr2)采用短路行为。也就是说,如果expr1是逻辑1 (true),则不评估expr2。
a,b和c的初始值为0。在表达式中:
++a || ++b && ++c;
++a->预递增a。
也就是说,表达式++a的值是a的增量值,该值将是1。由于||运算符具有短路行为,因此不会评估||的右侧表达式。因此,您将获得输出-1 0 0。
为了更好地理解,只需尝试在表达式中更改++a-> a++。
后递增运算符还将操作数的值增加1,但表达式的值是该操作数在增量运算之前的原始值。因此,a++将被评估为0,并且由于短路行为,将评估||运算符(++b && ++c)的右侧表达式。
逻辑AND操作(expr1 && expr2)也采用短路行为。如果发生逻辑短路,则只有当第一个操作数expr1不能完全确定结果时,才对第二个操作数expr2求值。也就是说,仅当expr1是逻辑1 (true)并且++b会导致1时,才会评估expr2。所以,如果你这样做
a++ || ++b && ++c;
^^^
输出将是-1 1 1。