逗号运算符如何工作

Joe*_*der 165 c++ comma-operator

逗号运算符如何在C++中工作?

例如,如果我这样做:

a = b, c;  
Run Code Online (Sandbox Code Playgroud)

最终是否等于b或c?

(是的,我知道这很容易测试 - 只是在这里记录,以便有人快速找到答案.)

更新: 此问题在使用逗号运算符时暴露了细微差别.只是记录下来:

a = b, c;    // a is set to the value of b!

a = (b, c);  // a is set to the value of c!
Run Code Online (Sandbox Code Playgroud)

这个问题实际上是受到代码中的拼写错误的启发.打算做什么

a = b;
c = d;
Run Code Online (Sandbox Code Playgroud)

转换成

a = b,    //  <-  Note comma typo!
c = d;
Run Code Online (Sandbox Code Playgroud)

Kon*_*lph 127

请注意,逗号运算符可能在C++中过载.因此,实际行为可能与预期的行为非常不同.

例如,Boost.Spirit非常巧妙地使用逗号运算符来实现符号表的列表初始值设定项.因此,它使以下语法成为可能且有意义:

keywords = "and", "or", "not", "xor";
Run Code Online (Sandbox Code Playgroud)

请注意,由于运算符优先级,代码(故意!)相同

(((keywords = "and"), "or"), "not"), "xor";
Run Code Online (Sandbox Code Playgroud)

也就是说,第一个被调用的运算符是keywords.operator =("and")返回一个代理对象,在该代理对象上operator,调用其余的s:

keywords.operator =("and").operator ,("or").operator ,("not").operator ,("xor");
Run Code Online (Sandbox Code Playgroud)

  • @Jeff恰恰相反.在列表周围有一个括号,这不起作用,因为编译器只看到两个`char []`之间的逗号运算符,它不能重载.代码*故意*先为每个剩余元素调用`operator =`然后调用`operator,`. (17认同)

efo*_*nis 122

逗号运算符具有所有C/C++运算符的最低优先级.因此,它始终是绑定到表达式的最后一个,这意味着:

a = b, c;
Run Code Online (Sandbox Code Playgroud)

相当于:

(a = b), c;
Run Code Online (Sandbox Code Playgroud)

另一个有趣的事实是逗号运算符引入了一个序列点.这意味着表达式:

a+b, c(), d
Run Code Online (Sandbox Code Playgroud)

保证按顺序评估其三个子表达式(a + b,c()d).如果它们有副作用,这是很重要的.通常,编译器可以按照他们认为合适的顺序评估子表达式; 例如,在函数调用中:

someFunc(arg1, arg2, arg3)
Run Code Online (Sandbox Code Playgroud)

可以按任意顺序评估参数.请注意,函数调用中的逗号不是运算符; 他们是分隔符.

  • 值得指出的是,``具有如此低的优先级,它甚至落后于_itself_;)......即:comma-as-_operator_的优先级低于逗号为_separator_.因此,如果要在单个函数参数,变量赋值或其他逗号_separated_列表中使用comma-as-_operator_,则需要使用括号,例如:`int a = 1,b = 2,weirdVariable =( ++ a,b),d = 4;` (13认同)

Leo*_*ans 73

它等于b.

逗号运算符的优先级低于赋值.


Cyg*_*sX1 63

逗号运算符:

  • 优先级最低
  • 是左联想的

为所有类型(内置和自定义)定义了默认版本的逗号运算符,它的工作方式如下 - 给定exprA , exprB:

  • exprA 被评估
  • 结果exprA被忽略了
  • exprB 被评估
  • 的结果exprB被返回作为整个表达式的结果

对于大多数运算符,允许编译器选择执行顺序,如果它不影响最终结果,甚至需要跳过执行(例如,false && foo()将跳过调用foo).然而,这不是逗号运算符的情况,并且上述步骤将始终发生*.

实际上,默认的逗号运算符的工作方式与分号几乎相同.不同之处在于,由分号分隔的两个表达式形成两个单独的语句,而逗号分隔将所有表达式保留为单个表达式.这就是为什么逗号运算符有时用于以下场景:

  • C语法需要单个表达式,而不是语句.例如inif( HERE )
  • C语法需要单个语句,而不是更多,例如在for循环的初始化中for ( HERE ; ; )
  • 当你想跳过花括号并保持一个声明:( if (foo) HERE ;请不要这样做,它真的很丑!)

如果语句不是表达式,则分号不能用逗号替换.例如,这些是不允许的:

  • (foo, if (foo) bar)(if不是表达)
  • int x,int y(变量声明不是表达式)

在您的情况下,我们有:

  • a=b, c;,相当于a=b; c;,假设该a类型不会使逗号运算符超载.
  • a = b, c = d;相当于a=b; c=d;,假设该a类型不会使逗号运算符重载.

请注意,并非每个逗号实际上都是逗号运算符.一些逗号含义完全不同:

  • int a, b; ---变量声明列表以逗号分隔,但这些不是逗号运算符
  • int a=5, b=3; ---这也是一个逗号分隔的变量声明列表
  • foo(x,y)---以逗号分隔的参数列表.事实上,x并且y可以在被评估的任何命令!
  • FOO(x,y) ---逗号分隔的宏参数列表
  • foo<a,b> ---逗号分隔的模板参数列表
  • int foo(int a, int b) ---逗号分隔的参数列表
  • Foo::Foo() : a(5), b(3) {} ---类构造函数中的逗号分隔的初始化列表

*如果您应用优化,则不完全正确.如果编译器认识到某段代码对其余代码完全没有影响,它将删除不必要的语句.

进一步阅读:http://en.wikipedia.org/wiki/Comma_o​​perator

  • 这个答案应该是公认的答案!感谢您的全面参考! (3认同)
  • 只是对类构造函数中逗号分隔的初始化列表稍加注释,顺序_不是_由列表中的位置决定。顺序由类的声明位置决定。例如`struct Foo { Foo() : a(5), b(3) {} int b; 一个; }` 在 `a(5)` 之前评估 `b(3)`。如果您的列表是这样的,这很重要:`Foo() : a(5), b(a) {}`。b 不会被设置为 5,而是 a 的未初始化值,您的编译器可能会或可能不会警告。 (2认同)

Mob*_*yDX 37

a将是b,但表达式的值将是c.也就是说,在

d = (a = b, c);
Run Code Online (Sandbox Code Playgroud)

a等于b,d等于c.

  • 差不多正确.表达式没有值,表达式也没有.该表达式的值是c. (18认同)

pra*_*ash 8

b的值将被分配给a.什么都不会发生在c