【问题标题】:C Operators and PrecedenceC 运算符和优先级
【发布时间】:2021-03-29 02:03:45
【问题描述】:

我用的是C语言,代码如下:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int num1=0;

    int res = ++num1 && num1++;

    printf("%d\t%d\n",num1,res);    
}

在上面的代码中,我得到的输出为2 1。我认为输出应该是2 0

如有错误请指正,为了解决这个语句,num1++(0) 将由于最高优先级而首先执行,然后 ++num1(2) 将被执行,最后 && 将被执行,因为它具有最低优先级。

请评论这条语句是如何执行的。

在一些教程中,我发现后缀 ++ 和前缀 ++ 具有相同的优先级,但如果这是真的,那么根据关联性规则再次 num1++ 应该首先执行(从右到左),这应该再次导致回答为2 0

【问题讨论】:

  • &amp;&amp; 是一个序列点。从Wikipedia开始保证之前评估的所有副作用都已执行,并且后续评估的副作用尚未执行。评价从左到右。
  • 即使 if 第二部分 num1++ (如你所料)首先被评估,这将评估为 0 和短电路规则会说,因为整个表达式不能是true,所以其他(第一)部分不会被评估,所以num1 不能像你想象的那样是2

标签: c operators operator-precedence sequence-points logical-and


【解决方案1】:

如有错误请指正,为了解决这个语句,num1++(0) 将由于最高优先级而首先执行,然后 ++num1(2) 将被执行,最后 && 将被执行,因为它具有最低优先级。

优先级仅控制哪些运算符与哪些操作数分组 - 它不影响计算表达式的顺序。

&amp;&amp;||?: 和逗号运算符都强制从左到右求值 - 左操作数在右操作数之前被完全求值(并应用任何副作用)。 &amp;&amp;||短路 - 对于&amp;&amp;,只有当左操作数不为零时才会计算右操作数。

一元(前缀)++ 运算符产生操作数的当前值加 1,因此++num1 的结果是1。作为副作用num1 中的值会增加。由于此结果不为零,因此还会评估 num1++。后缀++ 运算符产生操作数的当前值,因此num1++ 的结果是1。作为副作用,num1 中的值会增加。

&amp;&amp; 表达式的结果是 1,如果两个操作数都不为零,则 0 否则。

大致相当于写作

tmp = num1 + 1;
num1 = num1 + 1;

res = 0;
if ( tmp != 0 )
{
  if ( num1 != 0 )
  {
    res = 1;
  }
}
num1 = num1 + 1;

所以++num1 &amp;&amp; num1++结果1,而num1末尾存储的值为2

在一些教程中我发现后缀++和前缀++具有相同的优先级,

这是非常错误,您应该立即停止使用这些教程。后缀运算符的优先级高于一元运算符 - *a++ 被解析为 *(a++)++a[i] 被解析为 ++(a[i]) 等。像 ++i++ 这样的表达式将被解析为 ++(i++),但你不能在 C 中编写这样的表达式 - i++ 的结果不是 lvalue 并且不能是像这样的一元 ++ 的操作数。

【讨论】:

    【解决方案2】:

    在用作初始化器的表达式中

     int res = ++num1 && num1++;
    

    运算符&amp;&amp;有一个序列点。

    来自 C 标准(6.5.13 逻辑与运算符)

    3 如果两个操作数比较,&& 运算符将产生 1 不等于0;否则,它产生 0。结果的类型为 int。

    4 与按位二进制 & 运算符不同,&& 运算符保证 从左到右的评估;如果计算第二个操作数,则有 第一个和第二个评估之间的序列点 操作数。如果第一个操作数比较等于 0,则第二个操作数 未评估。

    首先计算运算符的左操作数,结果num1 将等于 1,因为一元(前缀)递增运算符。由于子表达式不等于 0,则计算第二个操作数。它的值是递增之前的值,即 1。由于第二个操作数也不等于 0,因此整个表达式被评估为逻辑真,其值为 1(参见 C 标准的第一个引号)。

    这个值 1 分配给变量 res 而后缀增量后的变量 num1 将等于 2。

    因此,在此声明之后,res 等于 1 并且 num1 等于 2

    【讨论】:

      【解决方案3】:

      这里有很多误解。首先,运算符优先级说明了解析的顺序,而不是执行的顺序。有两个相关但不同的术语,运算符优先级和评估顺序。
      What is the difference between operator precedence and order of evaluation?

      一旦您了解了求值顺序,&amp;&amp; 运算符就会特别带有明确定义的顺序,而 C 运算符通常不会出现这种情况。它保证了从左到右的评估顺序。 C17 6.5.14/4:

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

      通常情况下,您无法将 ++ 运算符与其他运算符混合使用,但上面的 && 规则使得在这种特定情况下成为可能。

      参见Why can't we mix increment operators like i++ with other operators? 它解释了排序/序列点。


      在一些教程中我发现后缀++和前缀++具有相同的优先级,

      他们没有,前缀 ++ 优先于后缀(和其他一元运算符)。所以关联性不适用。

      【讨论】:

        猜你喜欢
        • 2013-07-31
        • 1970-01-01
        • 2013-02-24
        • 2017-06-02
        • 1970-01-01
        • 2014-11-09
        • 2021-03-16
        • 2011-06-21
        相关资源
        最近更新 更多