需要解释输出结果的原因。

3

代码:

#include<stdio.h>
int main()
{
    int j = 7, i = 4;
    j = j || ++i && printf("you can");
    printf("%d %d",i,j);
    return 0;
}

输出结果: 4 1

[代码链接][1]

  1. 前缀运算符的优先级高于逻辑运算符。 2. 逻辑 && 的优先级高于逻辑 ||
  2. 在逻辑 AND (&&) 中,如果第一个操作数评估为 false,则不会评估第二个操作数;在逻辑 OR (||)) 中,如果第一个操作数评估为 true,则不会评估第二个操作数。
  3. 整个表达式评估为 true,因此 j 为 1。

疑问:

  1. Why the first rule is not followed here? Shouldn't it be correct?

    j=(j||((++i) &&printf("you can")));
    
因此,在printf语句中,i的值变为5。
为什么这里违反了一般的优先级规则?当两个运算符的优先级相同时,结合性就会发挥作用。编译器难道不应该首先确定是计算||还是&&吗?
如果首先计算||,那么结果是正确的,这是我所知道的。然而,如果它不是首先计算的,那么应该输出51。
4个回答

4
在这个表达式中:
j = j || ++i && printf("you can");

||之后有一个序列点,从左到右进行评估。由于j是非零的,表达式的其余部分不会被评估。因此,j || (....)变为真,即1。由于++i未被评估,i保持为4。因此,输出为4, 1
来自C标准:
引用:

附录C

以下运算符的第一个操作数的结尾:逻辑与&&(6.5.13); 逻辑或||(6.5.14); 条件?(6.5.15); 逗号,(6.5.17)。

如果你的j是零,则++i && printf("you can")将被评估,i将变为5,并且也将打印出you can。你对++的优先级比||更高是正确的,但由于存在序列点,j||首先被评估。

逻辑或运算符的两个操作数是j和++i,如果你说++i没有被评估,那么这是可以的,但为什么printf不行呢?难道不是printf在这里是AND运算符的一个操作数吗? - Tapasweni Pathak
因为&&具有更高的优先级,所以它被视为:j || (++i && printf("you can"))。由于存在中间序列点,j ||首先被计算。因此第二部分不会被计算。 - P.P

3

j || ++i && printf("you can") 的值为真,用 1 表示。由于它是一个 OR 运算符,并且 j 不为零,所以只有 OR 左手边被计算,因此 ++iprintf 都没有被计算。因此,j 是 1,i 保持在 4。

当然,真正的代码永远不应该像这样做任何事情。你应该总是以明显的运算顺序编写代码,并且几乎从不在 OR 语句中使用具有副作用的代码。


逻辑或运算符的两个操作数分别为j和++i,如果你说++i没有被评估也没关系,但为什么printf不行呢? - Tapasweni Pathak
2
@tapasweni:不,|| 的第二个操作数是表达式 ++i && printf("you can")。该表达式被解析为 j || (++i && printf("you can"))。由于 j 的值为非零,因此在 || 之后的所有内容都不会被计算。 - John Bode

2

你所拥有的:

j = j || ++i && printf("you can");

这是一个逻辑表达式(没有数学运算)。让我们分解一下:

++i                // as a mathematical expression this is i=i+1 (5 in your case)
printf("you can"); // printf returns the number of chars written, (7)

所以您期望这样:

j = 7 || 5 && 7;

上述表达式的输出只是1。因此,即使执行了这个表达式,你也应该看到j=1。那么为什么你看不到printf()的输出呢?
原因是整个表达式没有运行。它不需要运行。考虑以下情况:
result = TRUE || (anything else);

任何与其他内容“真实”或的东西都将始终返回true。编译器知道这一点,一旦它看到7 ||,就会将其等同于true ||并说:“我知道足够了,请将j设置为true并继续。”

这就是为什么表达式不会增加i并且不会打印“you can”的原因。 现在,如果您要翻转表达式:

j = ++i && printf("you can") || j; 

逻辑保持不变,但编译器在评估其他内容之前并未看到 || 运算符,因此 i 将被增加并且 printf 将被显示。


1

我以两种方式运行了这个程序:

j = j || ++i && printf("you can");

然后,就像这样:

j = j || (++i && printf("you can"));

两者的输出结果都是4 1。在运行它们之前,由于逻辑或的从左到右结合性,我预期会从两者中得到完全相同的结果。整个表达式将按照从左到右的顺序进行评估。括号的作用是确保一个表达式被评估为一个表达式,并不一定意味着它将是第一个要评估的表达式。如果您想获得更多证据,请尝试一些简单的操作:
j = 1 || (++i);

尽管(++i)在括号中,但它从未被评估。这是因为从左到右的结合性。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接