逗号运算符是如何工作的

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

例如,如果我这样做:

a = b, c;

结果是等于 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;
64044 次浏览

等于 b

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

B 的值将被分配给。 不会有事的

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

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

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

注意,由于操作符优先级的原因,代码(有意地)与

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

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

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

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

a的值将是 b,但是 表情的值将是 c

d = (a = b, c);

a等于 bd等于 c

逗号运算符具有所有 C/C + + 运算符的 最低优先级。因此它总是最后一个绑定到一个表达式,意思是:

a = b, c;

等同于:

(a = b), c;

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

a+b, c(), d

保证它的三个子表达式(A + bC ()D)按顺序计算。如果它们有副作用,这就很重要了。通常,编译器可以按照它们认为合适的顺序计算子表达式; 例如,在函数调用中:

someFunc(arg1, arg2, arg3)

参数可以按任意顺序计算。注意,函数调用中的逗号是 没有操作符; 它们是分隔符。

首先: 逗号实际上不是一个操作符,对于编译器来说,它只是一个标记,通过其他标记得到一个有意义的 在上下文中

这是什么意思,为什么这么麻烦?

例子一:

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

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

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

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

例二:

当我们编写一个具有多个初始化变量和/或多个表达式的典型 for 循环时,我们也使用逗号:

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

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

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

更复杂的是(在 C + + 中总是这样)逗号操作符本身可能会被重载(多亏了 康拉德 · 鲁道夫指出这一点)。

回到这个问题,准则

a = b, c;

对编译器来说意味着

(a = b), c;

因为 =令牌/操作符的 优先权高于 ,令牌的优先级。

这在上下文中被解释为

a = b;
c;

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

逗号运算符:

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

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

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

对于大多数运算符,编译器可以选择执行的顺序,如果不影响最终结果,甚至需要跳过执行(例如,false && foo()会跳过对 foo的调用)。然而,逗号运算符的情况并非如此,以上步骤总是发生在 *上。

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

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

当语句不是表达式时,分号不能用逗号替换,例如:

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

就你而言,我们有:

  • a=b, c;,等效于 a=b; c;,假设 a的类型不会重载逗号运算符。
  • 假设 a的类型不会重载逗号运算符,则 a = b, c = d;等效于 a=b; c=d;

请注意,并不是每个逗号实际上都是一个逗号运算符。有些逗号的意思完全不同:

  • int a, b;——-变量声明列表以逗号分隔,但这些不是逗号操作符
  • int a=5, b=3;——-这也是一个逗号分隔的变量声明列表
  • foo(x,y)——-逗号分隔的参数列表。事实上,xy可以按 任何顺序计算!
  • 以逗号分隔的宏参数列表
  • foo<a,b>——-逗号分隔的模板参数列表
  • int foo(int a, int b)——-逗号分隔的参数列表
  • 类构造函数中以逗号分隔的初始值设定项列表

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

延伸阅读: http://en.wikipedia.org/wiki/Comma_operator

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

#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
我们知道逗号运算符的优先级比赋值运算符的优先级低... ..。