逗号运算符如何工作以及它有什么优先级?
C++ 中的逗号运算符如何工作?
例如,如果我这样做:
a = b, c;
a 最终等于 b 或 c 吗?
(是的,我知道这很容易测试 - 只需在这里记录一下,以便其他人可以快速找到答案。)
更新:这个问题暴露了使用逗号运算符时的细微差别。 只是为了记录这一点:
a = b, c; // a is set to the value of b!
a = (b, c); // a is set to the value of c!
这个问题实际上是受到代码中的拼写错误的启发。 原本打算变成
a = b;
c = d;
什么
a = b, // <- Note comma typo!
c = d;
How does the comma operator work in C++?
For instance, if I do:
a = b, c;
Does a end up equaling b or c?
(Yes, I know this is easy to test - just documenting on here for someone to find the answer quickly.)
Update: This question has exposed a nuance when using the comma operator. Just to document this:
a = b, c; // a is set to the value of b!
a = (b, c); // a is set to the value of c!
This question was actually inspired by a typo in code. What was intended to be
a = b;
c = d;
Turned into
a = b, // <- Note comma typo!
c = d;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
是 逗号运算符的优先级低于赋值运算符
输出:i=3
因为逗号运算符总是返回最右边的值。
如果逗号运算符与赋值运算符一起使用:
输出:i=1
众所周知,逗号运算符的优先级低于赋值......
Yes Comma operator has low precedence than Assignment operator
Output : i=3
Because comma operator always return rightmost value.
In case of comma operator with Assignment Operator:
Ouput: i=1
As we know comma operator has lower precedence than assignment.....
a 的值将等于 b,因为逗号运算符的优先级低于赋值运算符。
The value of a will be equal to b, since the comma operator has a lower precedence than the assignment operator.
首先要做的事情:逗号实际上不是一个运算符,对于编译器来说,它只是一个标记,可以在上下文中与其他标记一起获得含义。
这意味着什么以及为什么要这么麻烦?
示例 1:
为了理解不同上下文中相同标记的含义之间的差异,我们看一下这个示例:
通常 C++ 初学者会认为这个表达式可以/会比较事物,但它是绝对错误,
<
、>
和,
标记的含义取决于使用上下文。对上面例子的正确解释当然是它是模板的实例化。
示例 2:
当我们编写一个典型的 for 循环时,该循环具有多个初始化变量和/或多个在循环每次迭代后应执行的表达式,我们也使用逗号:
逗号的含义取决于使用的上下文,这里是
for
构造的上下文。上下文中的逗号实际上意味着什么?
更复杂的是(在 C++ 中总是如此),逗号运算符本身可以被重载(感谢 Konrad Rudolph指出这一点)。
回到这个问题,代码
对于编译器来说意味着类似
因为优先级= 令牌/运算符的 a> 优先级高于
,
令牌。这是在上下文中解释的
(请注意,解释取决于上下文,这里它既不是函数/方法调用,也不是模板实例化。)
First things first: Comma is actually not an operator, for the compiler it is just a token which gets a meaning in context with other tokens.
What does this mean and why bother?
Example 1:
To understand the difference between the meaning of the same token in a different context we take a look at this example:
Usually a C++ beginner would think that this expression could/would compare things but it is absolutly wrong, the meaning of the
<
,>
and,
tokens depent on the context of use.The correct interpretation of the example above is of course that it is an instatiation of a template.
Example 2:
When we write a typically for loop with more than one initialisation variable and/or more than one expressions that should be done after each iteration of the loop we use comma too:
The meaning of the comma depends on the context of use, here it is the context of the
for
construction.What does a comma in context actually mean?
To complicate it even more (as always in C++) the comma operator can itself be overloaded (thanks to Konrad Rudolph for pointing that out).
To come back to the question, the Code
means for the compiler something like
because the priority of the
=
token/operator is higher than the priority of the,
token.and this is interpreted in context like
(note that the interpretation depend on context, here it it neither a function/method call or a template instatiation.)
b 的值将分配给 a。
c什么都不会发生
b's value will be assigned to a.
Nothing will happen to c
它等于
b
。逗号运算符的优先级低于赋值运算符。
It would be equal to
b
.The comma operator has a lower precedence than assignment.
a
的值将为b
,但表达式 的值将为c. 也就是说,
a
等于b
,d
等于c
。The value of
a
will beb
, but the value of the expression will bec
. That is, ina
would be equal tob
, andd
would be equal toc
.逗号运算符:
逗号运算符的默认版本是为所有类型(内置和自定义)定义的,其工作方式如下 - 给定
exprA , exprB
:exprA
的结果被忽略exprB
被计算exprB
的结果作为结果返回整个表达式对于大多数运算符,编译器可以选择执行顺序,甚至需要在不影响最终结果的情况下跳过执行(例如
false && foo()
将跳过对foo
的调用)。 然而,逗号运算符的情况并非如此,上述步骤总是会发生*。实际上,默认的逗号运算符的工作方式几乎与分号相同。 不同之处在于,用分号分隔的两个表达式形成两个单独的语句,而逗号分隔则将所有表达式保留为单个表达式。 这就是为什么逗号运算符有时会在以下场景中使用:
if( HERE )
中for
循环的初始化中for ( HERE ; ; )
if (foo) HERE ;
(请不要这样做,这真的很难看!)当语句不是表达式时,分号不能替换为逗号。 例如,这些是不允许的:
(foo, if (foo) bar)
(if
不是表达式)int 您的情况我们有:
a=b, c;
,相当于a=b; c;
,假设a
的类型不会重载逗号运算符。a = b, c = d;
相当于a=b; c=d;
,假设a
的类型不会重载逗号运算符。请注意,并非每个逗号实际上都是逗号运算符。 有些逗号具有完全不同的含义:
int a, b;
--- 变量声明列表是逗号分隔的,但这些不是逗号运算符int a=5, b=3;< /code> --- 这也是一个逗号分隔的变量声明列表
foo(x,y)
--- 逗号分隔的参数列表。 事实上,x
和y
可以按任何顺序进行计算!FOO(x,y)
--- 逗号分隔的宏参数列表foo
--- 逗号分隔的模板参数列表int foo( int a, int b)
--- 逗号分隔的参数列表Foo::Foo() : a(5), b(3) {}
--- 逗号分隔的初始值设定项list in a class constructor* 如果您应用优化,则情况并不完全正确。 如果编译器认识到某段代码对其余代码完全没有影响,它将删除不必要的语句。
进一步阅读:http://en.wikipedia.org/wiki/Comma_operator
The comma operator:
A default version of comma operator is defined for all types (built-in and custom), and it works as follows - given
exprA , exprB
:exprA
is evaluatedexprA
is ignoredexprB
is evaluatedexprB
is returned as the result of the whole expressionWith most operators, the compiler is allowed to choose the order of execution and it is even required to skip the execution whatsoever if it does not affect the final result (e.g.
false && foo()
will skip the call tofoo
). This is however not the case for comma operator and the above steps will always happen*.In practice, the default comma operator works almost the same way as a semicolon. The difference is that two expressions separated by a semicolon form two separate statements, while comma-separation keeps all as a single expression. This is why comma operator is sometimes used in the following scenarios:
if( HERE )
for
loopfor ( HERE ; ; )
if (foo) HERE ;
(please don't do that, it's really ugly!)When a statement is not an expression, semicolon cannot be replaced by a comma. For example these are disallowed:
(foo, if (foo) bar)
(if
is not an expression)In your case we have:
a=b, c;
, equivalent toa=b; c;
, assuming thata
is of type that does not overload the comma operator.a = b, c = d;
equivalent toa=b; c=d;
, assuming thata
is of type that does not overload the comma operator.Do note that not every comma is actually a comma operator. Some commas which have a completely different meaning:
int a, b;
--- variable declaration list is comma separated, but these are not comma operatorsint a=5, b=3;
--- this is also a comma separated variable declaration listfoo(x,y)
--- comma-separated argument list. In fact,x
andy
can be evaluated in any order!FOO(x,y)
--- comma-separated macro argument listfoo<a,b>
--- comma-separated template argument listint foo(int a, int b)
--- comma-separated parameter listFoo::Foo() : a(5), b(3) {}
--- comma-separated initializer list in a class constructor* This is not entirely true if you apply optimizations. If the compiler recognizes that certain piece of code has absolutely no impact on the rest, it will remove the unnecessary statements.
Further reading: http://en.wikipedia.org/wiki/Comma_operator
请注意,逗号运算符在 C++ 中可能会重载。 因此,实际行为可能与预期有很大不同。
例如,Boost.Spirit 非常巧妙地使用逗号运算符来实现符号表的列表初始值设定项。 因此,它使以下语法成为可能且有意义:
请注意,由于运算符优先级,代码(有意!)
与> 它返回一个代理对象,在该代理对象上调用其余的运算符:
Take care to notice that the comma operator may be overloaded in C++. The actual behaviour may thus be very different from the one expected.
As an example, Boost.Spirit uses the comma operator quite cleverly to implement list initializers for symbol tables. Thus, it makes the following syntax possible and meaningful:
Notice that due to operator precedence, the code is (intentionally!) identical to
That is, the first operator called is
keywords.operator =("and")
which returns a proxy object on which the remainingoperator,
s are invoked:逗号运算符在所有 C/C++ 运算符中具有最低优先级。 因此它总是最后一个绑定到表达式,这意味着:
相当于:
另一个有趣的事实是逗号运算符引入了 序列点。 这意味着表达式:
保证按顺序计算其三个子表达式(a+b、c() 和 d)。 如果它们有副作用,这一点就很重要了。 通常,编译器可以按照他们认为合适的任何顺序来计算子表达式; 例如,在函数调用中:
可以按任意顺序计算参数。 请注意,函数调用中的逗号是非运算符; 他们是分隔符。
The comma operator has the lowest precedence of all C/C++ operators. Therefore it's always the last one to bind to an expression, meaning this:
is equivalent to:
Another interesting fact is that the comma operator introduces a sequence point. This means that the expression:
is guaranteed to have its three subexpressions (a+b, c() and d) evaluated in order. This is significant if they have side-effects. Normally compilers are allowed to evaluate subexpressions in whatever order they find fit; for example, in a function call:
arguments can be evaluated in an arbitrary order. Note that the commas in the function call are not operators; they are separators.