【问题标题】:Explanation for this function's output此函数输出的说明
【发布时间】:2016-04-22 08:03:43
【问题描述】:

我正在做复习问题,问我“下面的输出是什么”,我在理解这个函数的一些问题时遇到了一些麻烦:

int a = 1, b = 1, c = -1;
c = --a && b++;
printf("%d %d %d", a, b, c);

输出是 010。我的问题是关于第 2 行,c = --a && b++。这条线是如何处理的,它是如何工作/改变值的?如果是c = --a || b++?据我了解,我认为输出将是 020。

【问题讨论】:

标签: c output logical-operators integer-arithmetic


【解决方案1】:

理解结果的关键概念是布尔运算符的short-circuit evaluation&&||)——如果在评估布尔运算符的左侧之后,右侧的值不能影响整体结果,则不会被评估也不会产生任何副作用

在第一种情况下,由于 --a 的计算结果为 0 (=false),因此不会计算 ... && ... 的第二部分,因为“false AND anything”将始终为 false。具体来说,b++ 永远不会被执行,因此它的值在输出中仍然是1

--a || b++的情况下,整个表达式的值不能由左侧确定(“false OR something”仍然可以为true ) 所以b++ 被评估的(它的副作用,增加b,发生)。

完全理解结果所需的另一个概念是前后递增/递减运算符之间的区别。如果--++ 出现在变量之前(如--a),则变量首先递减或递增,new 值用于评估整个表达。如果--++ 出现在变量之后(如b++),则变量的当前 值用于计算表达式和增量/decrement 发生在这之后。

应该注意的是,试图组合两个或多个--/++ 实例的表达式同一个变量(例如a++ + ++a)很有可能调用undefined behaviour -- 结果可能因平台、编译器、编译器甚至一天中的时间而异。

【讨论】:

  • 一个完整的答案应该优先涉及前增量和后增量之间的区别
【解决方案2】:

在表达式c = --a && b++ 中,a 被减少并返回。现在表达式--a && b++ 的第二个参数没有被计算,因为short circuit evaluation---一旦我们看到--a==0,我们已经知道表达式将是0 不管是什么另一个论点---,所以b 保持不变。

减少的a0,而b 仍然是1

正如你所建议的,输出是0 1 0

关于第二个问题,如果你写c = --a || b++,变量a又变为零,但表达式仍然可以计算为真——因此我们必须计算第二部分,从而执行b++它返回1 并增加b。在这种情况下,输出将是0 2 1,因为c 被分配了0 || 1 的值,即1

简而言之,请继续阅读

【讨论】:

  • 是的,因为short circuit evaluation;我更新了答案
  • 缺少的部分是--a && b++ 短路。 --a 是假的,所以 b++ 永远不会被执行。
【解决方案3】:

这里首先需要关注的是前缀和后缀运算符的属性及其区别。

  • 对于后缀递增和递减运算符,C11,第 §6.5.2.4 章,(强调我的

    后缀++ 运算符的结果是操作数的值。作为一个副作用, 操作数对象的值递增 [...] 后缀 -- 运算符类似于后缀 ++ 运算符,不同之处在于 操作数递减。

  • 对于前缀递增和递减运算符,C11,第 §6.5.3.1 章,(强调我的

    前缀++运算符的操作数的值递增。结果是新的 递增后操作数的值。 [...] 前缀 -- 运算符类似于前缀 ++ 运算符,除了 操作数递减。

现在,出现了逻辑与 (&&) 运算符的属性。从第 §6.5.13 章开始,(再次强调我的

&& 运算符保证从左到右的评估; 如果对第二个操作数求值,则在求值之间存在一个序列点 第一个和第二个操作数。 如果第一个操作数比较等于 0,则第二个 不计算操作数。 [...]

所以,在你的情况下,

int a = 1, b = 1, c = -1;
c = --a && b++;

被评估为

c = 0 && .....; // done..., a is decremented to 0, 
                //            so, LHS of && is 0, RHS is not evaluated,
                //            b remains 1
                //            and finally, C gets 0.

另一方面,如果使用逻辑 OR (||),则根据第 6.5.14 章中提到的属性

[...] || 运算符保证从左到右的评估;如果 第二个操作数被求值,第一个求值之间有一个序列点 和第二个操作数。 如果第一个操作数比较不等于 0,则第二个操作数为 未评估。

所以,对于这种情况

int a = 1, b = 1, c = -1;
c = --a || b++;

它将被评估为

c = 0 || 1;   //yes, b's value will be used, and then incremented.

所以,

printf("%d %d %d", a, b, c);

将会

0 2 1

【讨论】:

    【解决方案4】:

    b++ 根本不会执行,因为 --a 在 and 条件下的计算结果为 false。 and 的右侧永远不会执行,因为不需要。因此 b 永远不会增加,因此输出是您没想到的。

    【讨论】:

      【解决方案5】:
      c = --a && b++;
      

      在这第一个 --a 被评估并且 a 变为 0 ,只要 && 的一个操作数是 false ,b++ 不会被评估,因此,b 仍然是 1 和 @ 987654329@ 变为 0

      【讨论】:

        【解决方案6】:

        行:

        c = --a && b++;
        

        a 减少到0,因此语句0 && anything else 结果为0。这就是为什么ac 结果为0,您似乎已经理解了。

        现在让我们看看你没有得到的部分。当a求值为0时,&&的右边部分不需要求值,因为不管右边部分的值是多少,结果都是0。这意味着b++ 不会被评估,因此b 将保留其初始值。这就是为什么您看到值1 而不是2,因此输出0 1 0 而不是0 2 0

        【讨论】:

          【解决方案7】:

          --a :意味着您在执行该行之前减少 a 。 b++:在行后增加 b。使得c(当时)=0+1=1;那么:a=0,b=2,c=1;好的

          【讨论】:

          • 哦,我误解了 && 与 +。
          猜你喜欢
          • 1970-01-01
          • 2019-08-31
          • 1970-01-01
          • 2011-02-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-06-24
          相关资源
          最近更新 更多