在 C 中使用 ++ 运算符对语句进行短路评估

Posted

技术标签:

【中文标题】在 C 中使用 ++ 运算符对语句进行短路评估【英文标题】:Short circuit evaluation of a statement with ++ operator in C 【发布时间】:2015-10-25 02:16:39 【问题描述】:

我在 Windows 7 上的 Code::Blocks 10.05 中执行了以下代码。

int a=0,b=0,c;
c=a++&&b++;
printf("\na=%d\nb=%d\nc=%d\n\n",a,b,c);

我得到的输出如下,

a=1
b=0
c=0

由于短路评估,这非常有意义。

表达式a++ 是后增量,0 返回逻辑与 (&&)。因此,b++ 部分没有被评估,因为0 && 00 && 1 的计算结果为 0

但是这里出现了我的疑问。运算符的优先级值清楚地表明++ 的优先级高于&&。所以我的理解是这样的,a++ 和 b++ 都被评估,然后&& 只检查表达式a++ 的结果来做出决定。但这并没有发生,只有a++ 在这里被评估。

这种行为的原因是什么? && 作为序列点是否与此行为有关?如果是这样,为什么我们说&& 的优先级低于++

【问题讨论】:

在它们之上还有一条规则,a++ 只会在语句执行后递增。因此,无论它的优先级是什么,它都会在语句完成后递增。 哇,这是一个可恶的陷阱。 除了这个问题有趣的语言方面,我建议让您的代码立即清晰易读。目前情况并非如此。 我认为这样的代码得到了任何支持,这很可悲。 @saurabhagarwal a++ 将在评估 a 和语句完成之间的某个不确定时间递增。这就是为什么你不能在同一个表达式中再次使用a(在a++ 之前或之后)。 【参考方案1】:

这里有两个概念 - 优先顺序和评估顺序。只有在计算表达式(或子表达式)时,优先顺序才会产生影响。

一般来说,评估的顺序是不分先后的。给定一个运算符,它的操作数可以按任何顺序求值。函数的参数可以按任意顺序计算。

来自 C++ 标准:

1.9 程序执行

15 除非另有说明,否则单个运算符的操作数和单个表达式的子表达式的求值是无序的。

8.3.6 默认参数

9 每次调用函数时都会评估默认参数。函数参数的求值顺序未指定。

对于逻辑与运算符&&,C++11 标准规定:

5.14 逻辑与运算符

1 && 运算符从左到右分组。操作数都根据上下文转换为 bool 类型(第 4 条)。如果两个操作数都是true,则结果为true,否则为false。与& 不同,&& 保证从左到右求值:如果第一个操作数是 false,则不求第二个操作数。

为逻辑 OR 运算符 || 指定了类似的异常。

由于&& 运算符导致表达式短路,b++ 未被计算,因此运算符的优先顺序在这种特殊情况下没有意义。

【讨论】:

说“优先顺序”会混淆问题,“评估顺序”和“优先顺序”需要分开【参考方案2】:

您对优先级评估顺序感到困惑。

优先级定义了运算符的分组方式,即

c = a++ && b++;

相当于:

c = ((a++) && (b++));

求值顺序定义了表达式的求值方式,&&短路表示a++先求值,如果为零,则结束;如果不为零,则评估 b++


再举一个例子:

c = (a++) + (b++);

a++ 是否在 b++ 之前进行评估?答案是我们不知道。大多数运算符不定义评估顺序。 && 是少数定义的运算符之一。 (其余为||,?:

【讨论】:

另一种说法是 && 在其左参数的求值之后和第二个参数的求值之前定义了一个序列点。没有为 + 定义序列点。***有一篇关于序列点的好文章。

以上是关于在 C 中使用 ++ 运算符对语句进行短路评估的主要内容,如果未能解决你的问题,请参考以下文章

当运算符优先级说不应该时,为啥短路评估会起作用?

三元运算符可以等效于与逻辑运算符的短路吗?

短路评估顺序和前缀增量运算符

短路逻辑评估运算符

使用三元运算符或仅短路评估之间的区别?

使用 && 进行单线短路评估 ||在 JavaScript 中