逗号操作符如何工作?
逗号操作符如何在C ++中工作?
例如,如果我这样做:
a = b, c;
最后等于b还是c?
(是的,我知道这很容易testing – 只需在这里logging下来,以便快速find答案)。
更新:使用逗号运算符时,这个问题暴露了一个细微之处。 只是为了certificate这一点:
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;
这将等于b
。
逗号运算符的优先级低于赋值。
请注意,逗号运算符可能在C ++中超载。 实际行为可能与预期的行为有很大的不同。
作为一个例子, Boost.Spirit使用逗号运算符来巧妙地实现符号表的列表初始值设定项。 因此,它使以下语法成为可能和有意义的:
keywords = "and", "or", "not", "xor";
请注意,由于运算符的优先级,代码(有意!)完全相同
(((keywords = "and"), "or"), "not"), "xor";
也就是说,被调用的第一个运算符是keywords.operator =("and")
,它返回一个代理对象,其余的operator,
被调用:
keywords.operator =("and").operator ,("or").operator ,("not").operator ,("xor");
逗号运算符在所有C / C ++运算符中的优先级最低 。 因此,它总是最后一个绑定到一个expression式,这意味着:
a = b, c;
相当于:
(a = b), c;
另一个有趣的事实是,逗号运算符引入了一个序列点 。 这意味着expression式:
a+b, c(), d
保证有三个子expression式( a + b , c()和d )按顺序进行评估。 如果他们有副作用,这是重要的。 通常编译器可以按照他们认为合适的顺序来评估子expression式; 例如,在函数调用中:
someFunc(arg1, arg2, arg3)
参数可以以任意顺序评估。 请注意,函数调用中的逗号不是运算符; 他们是分隔符。
逗号运算符:
- 优先级最低
- 是左联合的
为所有types(内置和自定义)定义了默认版本的逗号运算符,它的工作原理如下 – 给定exprA , exprB
:
-
exprA
被评估 -
exprA
的结果被忽略 -
exprB
被评估 -
exprB
的结果作为整个expression式的结果返回
对于大多数操作符,编译器可以select执行的顺序,甚至可以不执行任何操作,如果不影响最终结果(例如false && foo()
将跳过对foo
的调用)。 然而,逗号运算符并不是这样,上述步骤总是会发生* 。
实际上,默认的逗号运算符与分号几乎相同。 不同之处在于用分号分隔的两个expression式形成了两个单独的语句,而逗号分隔则保留为单个expression式。 这就是为什么逗号运算符有时用于以下场景:
- C语法需要一个expression式 ,而不是一个语句。 例如在
if( HERE )
- C语法需要一个单独的语句,而不是更多,例如在
for ( HERE ; ; )
for
循环的初始化中, - 如果你想跳过花括号,并保持一个单一的声明:
if (foo) HERE ;
(请不要这样做,真的很难看!)
当语句不是expression式时,分号不能用逗号replace。 例如,这些是不允许的:
-
(foo, if (foo) bar)
(if
不是expression式) - int x,int y(variables声明不是expression式)
在你的情况下,我们有:
-
a=b, c;
,相当于a=b; c;
a=b; c;
假设a
的types不会超出逗号操作符。 -
a = b, c = d;
相当于a=b; c=d;
a=b; c=d;
假设a
的types不会超出逗号操作符。
请注意,并非每个逗号实际上都是一个逗号运算符。 一些逗号有完全不同的含义:
-
int a, b;
—variables声明列表是用逗号分隔的,但是这些不是逗号操作符 -
int a=5, b=3;
—这也是逗号分隔的variables声明列表 -
foo(x,y)
—逗号分隔的参数列表。 事实上,x
和y
可以按任何顺序进行评估! -
FOO(x,y)
—逗号分隔的macros参数列表 -
foo<a,b>
—逗号分隔的模板参数列表 -
int foo(int a, int b)
—逗号分隔参数列表 -
Foo::Foo() : a(5), b(3) {}
—类构造函数中的逗号分隔初始值设定项列表
*如果应用优化,这并不完全正确。 如果编译器意识到某段代码对其余部分完全没有影响,它将删除不必要的语句。
进一步阅读: http : //en.wikipedia.org/wiki/Comma_operator
a的值将是b
,但expression式的值将是c
。 那就是,
d = (a = b, c);
a等于b
, d
等于c
。
b的价值将被分配给a。 什么都不会发生
a的值将等于b,因为逗号运算符的优先级比赋值运算符的优先级低。
是逗号运算符优先级低于赋值运算符
#include<stdio.h> int main() { int i; i = (1,2,3); printf("i:%d\n",i); return 0; }
输出:i = 3
因为逗号运算符总是返回最右边的值。
如果是分配运营商的逗号运算符:
int main() { int i; i = 1,2,3; printf("i:%d\n",i); return 0; }
输出:i = 1
因为我们知道逗号运算符的优先级比赋值低
首先, Comma实际上不是一个运算符,因为编译器只是一个与其他令牌相关的令牌。
这是什么意思,为什么打扰?
例1:
为了理解不同情况下同一个标记的含义之间的区别,我们看一下这个例子:
class Example { Foo<int, char*> ContentA; }
通常一个C ++初学者会认为这个expression式可以/会比较一些东西,但绝对是错误的, <
, >
和令牌的含义依赖于使用的上下文。
上面例子的正确解释当然是它是一个模板的安装。
例2:
当我们使用多个初始化variables和/或在循环的每次迭代之后应该完成的多个expression式来编写循环时,我们也使用逗号:
for(a=5,b=0;a<42;a++,b--) ...
逗号的含义取决于使用的上下文,这里就是构造的上下文。
上下文中的逗号究竟意味着什么?
为了使它更复杂(像C ++一样),逗号运算符本身可能会超载(感谢Konrad Rudolph指出了这一点)。
回到问题,守则
a = b, c;
意味着编译器的东西
(a = b), c;
因为=
token / operator的优先级高于token的优先级。
这是在上下文中解释的
a = b; c;
(注意解释依赖于上下文,在这里它既不是函数/方法调用,也不是模板的安装)。