[英]Is it safe to put increment/decrement operators inside ternary/conditional operators?
Here's an example 这是一个例子
#include <iostream>
using namespace std;
int main()
{
int x = 0;
cout << (x == 0 ? x++ : x) << endl; //operator in branch
cout << "x=" << x << endl;
cout << (x == 1 || --x == 0 ? 1 : 2) << endl; //operator in condition
cout << "x=" << x << endl;
return 0;
}
output: 输出:
0
x=1
1
x=1
I understand the output, but is this undefined behaviour or not? 我理解输出,但这是不确定的行为? Is the order of evaluation guaranteed in either case?
在任何一种情况下,评估顺序是否得到保证?
Even if guaranteed, I'm quite aware using increment/decrement can quickly become an issue for readability. 即使有保证,我也非常清楚使用递增/递减会很快成为可读性的问题。 I only ask as I saw similar code and was immediately unsure, given there are lots of examples of ambiguous/undefined use of increment/decrement operators, such as...
我只是问我看到类似的代码并且立即不确定,因为有很多关于递增/递减运算符的模糊/未定义使用的示例,例如......
C++ does not define the order in which function parameters are evaluated.
C ++没有定义评估函数参数的顺序。 ↪
↪
int nValue = Add(x, ++x);
The C++ language says you cannot modify a variable more than once between sequence points.
C ++语言表示你不能在序列点之间多次修改变量。 ↪
↪
x = ++y + y++
Because increment and decrement operators have side effects, using expressions with increment or decrement operators in a preprocessor macro can have undesirable results.
因为递增和递减运算符具有副作用,所以在预处理器宏中使用具有递增或递减运算符的表达式可能会产生不良结果。 ↪
↪
#define max(a,b) ((a)<(b))?(b):(a) k = max( ++i, j );
For the conditional operator (§5.16 [expr.cond]/p1): 对于条件运算符(§5.16[expr.cond] / p1):
Every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second or third expression.
在与第二或第三表达式相关联的每个值计算和副作用之前,对与第一表达式相关联的每个值计算和副作用进行排序。
For the logical OR operator (§5.15 [expr.log.or]/p1-2): 对于逻辑OR运算符(§5.15[expr.log.or] / p1-2):
the second operand is not evaluated if the first operand evaluates to
true
.如果第一个操作数的计算结果为
true
则不计算第二个操作数。 [...] If the second expression is evaluated, every value computation and side effect associated with the first expression is sequenced before every value computation and side effect associated with the second expression.[...]如果计算第二个表达式,则在每个值计算和与第二个表达式相关的副作用之前,对与第一个表达式相关联的每个值计算和副作用进行排序。
The behavior of your code is well-defined. 代码的行为是明确定义的。
There is a guaranteed order of execution in ternary operators and boolean &&
and ||
在三元运算符中有保证的执行顺序和boolean
&&
和||
operations, so there is no conflict in evaluation sequence points. 操作,因此评估序列点没有冲突。
One at a time 一次一个
cout << (x == 0 ? x++ : x) << endl; //operator in branch
Will always output x
but will increment it only if it was 0. 将始终输出
x
但仅在它为0时才会递增。
cout << (x == 1 || --x == 0 ? 1 : 2) << endl; //operator in condition
This is well defined too, if x
was 1 it will not evaluate the RHS, if it wasn't it will decrement it but --x
will never be 0, so it will be true iff x==1, in which case x
will also now be 0. 这个定义也很明确,如果
x
为1,它将不会评估RHS,如果不是它将减少它但--x
将永远不会为0,所以如果f = = 1则为真,在这种情况下x
现在也将是0。
In the latter case if x is INT_MIN
it is not well-defined behaviour to decrement it (and it would execute). 在后一种情况下,如果x是
INT_MIN
那么递减它就不是明确定义的行为(并且它将执行)。
That can't happen in the first case where x won't be 0 if it is INT_MAX
so you are safe. 如果它是
INT_MAX
那么在x不会为0的第一种情况下不会发生这种情况,因此您是安全的。
I understand the output, but is this undefined behaviour or not?
我理解输出,但这是不确定的行为?
Code is perfectly defined. 代码完美定义。 C11 standard says:
C11标准说:
The first operand is evaluated;
第一个操作数被评估; there is a sequence point between its evaluation and the evaluation of the second or third operand (whichever is evaluated).
在其评估与第二或第三操作数的评估之间存在一个序列点 (以评估者为准)。 The second operand is evaluated only if the first compares unequal to
0
;仅当第一个操作数不等于
0
时才评估第二个操作数; the third operand is evaluated only if the first compares equal to0
;仅当第一个操作数比较等于
0
时才评估第三个操作数; the result is the value of the second or third operand (whichever is evaluated), converted to the type described below.110)结果是第二个或第三个操作数的值(无论哪个被评估),转换为下面描述的类型.110)
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.如果第一个操作数比较不等于
0
,则不计算第二个操作数。
Further wiki explains it with example: 进一步维基用例子解释:
Between evaluation of the left and right operands of the
&&
(logical AND),||
在评估
&&
(逻辑AND)的左右操作数之间,||
(logical OR) (as part of short-circuit evaluation), andcomma operators
.(逻辑OR)(作为短路评估的一部分)和
comma operators
。 For example, in the expression*p++ != 0 && *q++ != 0
, all side effects of the sub-expression*p++ != 0
are completed before any attempt to accessq
.例如,在表达式
*p++ != 0 && *q++ != 0
,子表达式*p++ != 0
所有副作用都在任何尝试访问q
之前完成。Between the evaluation of the first operand of the ternary "question-mark" operator and the second or third operand.
在评估三元“问号”运算符的第一个操作数和第二个或第三个操作数之间。 For example, in the expression
a = (*p++) ? (*p++) : 0
例如,在表达式
a = (*p++) ? (*p++) : 0
a = (*p++) ? (*p++) : 0
there is a sequence point after the first*p++
, meaning it has already been incremented by the time the second instance is executed.a = (*p++) ? (*p++) : 0
在第一个*p++
之后有一个序列点,这意味着它已经在第二个实例执行时增加了。
The rule for ||
||
的规则 and ?:
is same for C++ (section 5.15 and 5.16) as in C. 和
?:
C ++(第5.15和5.16节)与C相同
Is the order of evaluation guaranteed in either case?
在任何一种情况下,评估顺序是否得到保证?
Yes. 是。 The order of evaluation of the operands of operators
||
运算符
||
的操作数的评估顺序 , &&
, ,
and ?:
is guaranteed to be from left to right. ,
&&
, ,
和?:
保证是由左到右。
In C an object's stored value can be modified only once between two sequence points. 在C中,对象的存储值只能在两个序列点之间修改一次。
A sequence point occurs: 出现一个序列点:
&&
, ||
&&
, ||
and ?:
operators ?:
运营商 So for example this expression x = i++ * i++
is undefined , whereas x = i++ && i++
is perfectly legal . 因此,例如,这个表达式
x = i++ * i++
是未定义的 ,而x = i++ && i++
是完全合法的 。
Your code shows defined behaviour . 您的代码显示已定义的行为
int x=0;
int x = 0;
cout << ( x == 0 ? x++ : x) << endl;
cout <<(x == 0?x ++:x)<< endl;
In the above expression x
is 0
, so x++
will be executed, here x++ is post increment so it will output 0
. 在上面的表达式中,
x
是0
,所以x++
将被执行,这里x ++是后递增的,所以它将输出0
。
cout << "x=" << x << endl;
cout <<“x =”<< x << endl;
In the above expression as x
now has value 1
so the output will be 1
. 在上面的表达式中,
x
现在的值为1
因此输出将为1
。
cout << (x == 1 || --x == 0 ? 1 : 2) << endl;
cout <<(x == 1 || --x == 0?1:2)<< endl;
Here x
is 1
so the next condition is not evaluated( --x == 0
) and the output will 1
. 这里
x
是1
因此不评估下一个条件( --x == 0
),输出将为1
。
cout << "x=" << x << endl;
cout <<“x =”<< x << endl;
As the expression --x == 0
is not evaluated the output will again be 1
. 由于未评估表达式
--x == 0
,输出将再次为1
。
Yes, it is safe to use the increment/decrement operators as you have. 是的,使用增量/减量运算符是安全的。 Here is what is happening in your code:
以下是代码中发生的情况:
cout << (x == 0 ? x++ : x) << endl; //operator in branch
In this snippet, you are testing if x == 0
, which is true
. 在这个片段中,您正在测试
x == 0
,这是true
。 Since it is true
, your ternary expression evaluates the x++
. 因为它是
true
,你的三元表达式会评估x++
。 Since you are using a post-increment here, the original value for x
is printed to the standard output stream, and then x
is incremented. 由于您在此处使用后增量,因此
x
的原始值将打印到标准输出流, 然后 x
递增。
cout << (x == 1 || --x == 0 ? 1 : 2) << endl; //operator in condition
This snippet is a bit more confusing, but it still yields a predictable result. 这个片段有点混乱,但它仍然会产生可预测的结果。 At this point,
x = 1
from the first snippet. 此时,第一个片段的
x = 1
。 In the ternary expression, the conditional part is evaluated first; 在三元表达式中,首先评估条件部分; however, due to Short-Circuiting , the second condition,
--x == 0
, is never evaluated. 但是,由于短路 , 第二个条件
--x == 0
,永远不会被评估。
For C++ the operators ||
对于C ++运算符
||
and &&
are the short-circuiting boolean operators for logical OR and logical AND respectively. 和
&&
分别是逻辑OR和逻辑AND的短路布尔运算符。 When you use these operators, your conditions are checked (from left to right) until the final result can be determined. 使用这些运算符时,会检查您的条件(从左到右),直到确定最终结果。 Once the result is determined, no more conditions are checked.
确定结果后,不再检查条件。
Looking at snippet #2, your first condition checks if x == 1
. 查看代码片段#2,您的第一个条件检查
x == 1
。 Since your first condition evaluates to true
and you are using the logical OR, there is no need to keep evaluating other conditions. 由于您的第一个条件评估为
true
并且您正在使用逻辑OR,因此无需继续评估其他条件。 That means that --x == 0
is never executed . 这意味着
--x == 0
永远不会执行 。
Short-circuiting is useful for increasing performance in your program. 短路对于提高程序性能非常有用。 Suppose you had a condition like this which calls several time-expensive functions:
假设您有这样的条件,它会调用几个耗时的函数:
if (task1() && task2())
{
//...Do something...
}
In this example, task2
should never be called unless task1
completes successfully ( task2
depends on some data that is altered by task1
). 在这个例子中,
task2
不应该被称为除非task1
成功完成( task2
取决于是通过改变一些数据task1
)。
Because we are using a short-circuiting AND operator , if task1
fails by returning false
, then if-statement has the sufficient information to exit early and stop checking other conditions. 因为我们使用的是短路AND运算符 ,如果
task1
因返回false
失败,那么if-statement有足够的信息提前退出并停止检查其他条件。 This means that task2
is never called. 这意味着永远不会调用
task2
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.