187

逗号运算符在 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;
4

9 回答 9

133

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

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

keywords = "and", "or", "not", "xor";

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

(((keywords = "and"), "or"), "not"), "xor";

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

keywords.operator =("and").operator ,("or").operator ,("not").operator ,("xor");
于 2008-09-10T14:21:54.993 回答
130

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

a = b, c;

相当于:

(a = b), c;

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

a+b, c(), d

保证按顺序计算其三个子表达式(a+bc()d )。如果它们有副作用,这很重要。通常允许编译器以他们认为合适的任何顺序来评估子表达式。例如,在函数调用中:

someFunc(arg1, arg2, arg3)

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

于 2008-09-22T11:49:36.230 回答
77

这将等于b

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

于 2008-09-10T14:14:27.910 回答
73

逗号运算符:

  • 具有最低优先级
  • 是左结合的

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

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

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

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

  • C 语法需要单个表达式,而不是语句。例如在if( 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

于 2013-10-05T14:43:20.383 回答
40

a的值为b,但表达式的值为c。也就是说,在

d = (a = b, c);

a将等于b,并且d将等于c

于 2008-09-15T18:29:25.323 回答
8

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

于 2008-09-10T14:16:54.113 回答
3

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

#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
正如我们所知,逗号运算符的优先级低于赋值......

于 2015-07-04T13:31:23.830 回答
2

a 的值将等于 b,因为逗号运算符的优先级低于赋值运算符。

于 2008-09-10T14:22:01.967 回答
-3

首先要做的事情:逗号实际上不是运算符,对于编译器来说,它只是一个在上下文中与其他标记一起获得含义的标记。

这是什么意思,为什么要打扰?

示例 1:

为了理解不同上下文中相同标记的含义之间的差异,我们看一下这个例子:

class Example {
   Foo<int, char*> ContentA;
}

通常 C++ 初学者会认为这个表达式可以/会比较事物,但这是绝对错误的,<>的含义,取决于使用的上下文。

对上面例子的正确解释当然是它是一个模板的实例化。

示例 2:

当我们编写一个具有多个初始化变量和/或多个表达式的典型 for 循环时,应该在循环的每次迭代之后完成,我们也使用逗号:

for(a=5,b=0;a<42;a++,b--)
   ...

逗号的含义取决于使用的上下文,这里是for构造的上下文。

上下文中的逗号实际上是什么意思?

更复杂的是(在 C++ 中总是如此),逗号运算符本身可以被重载(感谢Konrad Rudolph指出这一点)。

回到这个问题,守则

a = b, c;

对编译器来说意味着类似

(a = b), c;

因为token/operator的优先=级高于,token的优先级。

这在上下文中被解释为

a = b;
c;

(请注意,解释取决于上下文,这里它既不是函数/方法调用也不是模板实例化。)

于 2013-04-07T10:39:17.477 回答