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


评论

在此处了解更多信息。 stackoverflow.com/questions/12824378 / ...

逗号运算符`,`在C中做什么的可能重复项?败了你一天。 lillq的答案为有关a =(b,c);的问题提供了答案。

但是在这种情况下,a = b,c = d;实际上确实与预期的a = b表现相同; c = d ;?

@NargothBond不一定。如果b和d是使用(并修改)公共状态的函数求值,则直到C ++ 17才定义执行顺序。

#1 楼

等于b

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

#2 楼

请注意,逗号操作符在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");


评论


嗯,不过您不能更改优先级,这意味着您应该在列表中加上括号。

–杰夫·伯吉斯(Jeff Burdges)
2011年10月8日18:56

@Jeff相反。在列表中加上括号后,此操作将无效,因为编译器仅会看到两个char []之间的逗号运算符,不能重载。对于每个剩余元素,该代码有意先调用operator =,然后再调用operator。

–康拉德·鲁道夫(Konrad Rudolph)
2011年10月9日,11:04

#3 楼

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

a = b, c;


等效于:

(a = b), c;


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

a+b, c(), d


确保按顺序对其三个子表达式(a + b,c()和d)求值。如果它们有副作用,这是很重要的。通常,允许编译器以它们认为合适的任何顺序评估子表达式。例如,在函数调用中:

someFunc(arg1, arg2, arg3)


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

评论


值得指出的是,,具有如此低的优先级,它甚至落后于自身;)...也就是说:逗号分隔符的优先级比逗号分隔符的优先级低。因此,如果要在单个函数参数,变量赋值或其他逗号分隔的列表中使用逗号运算符-那么您需要使用括号,例如:int a = 1,b = 2,weirdVariable =(+ + a,b),d = 4;

– underscore_d
16-4-16在21:45



#4 楼

逗号运算符:


具有最低的优先级
是左关联的

为所有类型定义了默认版本的逗号运算符(内置in和custom中),它的工作方式如下-给出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) ---逗号分隔的参数列表。实际上,xy可以按任何顺序求值!

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

评论


值得注意的是,如果operator过载,您将失去对关联性的任何保证(就像您过载了operator &&和operator ||的短路特性一样)?

– YoungJohn
16-2-22在16:44

逗号运算符是左关联的,无论它是否过载。表达式a,b,c始终表示(a,b),c,从不表示a,(b,c)。如果元素的类型不同,则后一种解释甚至可能导致编译错误。对参数的求值顺序可能是什么?我不确定,但是也许您是对的:即使逗号是左关联的,也可能会在(a,b)之前对c进行求值。

– CygnusX1
16-2-22在17:15

仅对类构造函数中以逗号分隔的初始化列表进行一点注释,顺序不取决于列表中的位置。顺序由类的声明位置确定。例如。 struct Foo {Foo():a(5),b(3){} int b;诠释}在a(5)之前对b(3)进行运算。如果您的列表如下所示,这很重要:Foo():a(5),b(a){}。 b不会设置为5,而是a的未初始化值,您的编译器可能会或可能不会发出警告。

–乔纳森·高里奇(Jonathan Gawrych)
18年7月29日在2:55



我最近遇到了一个带有两个浮点数的逗号运算符,求值和舍弃数字的意义是什么?

–亚伦·弗兰克(Aaron Franke)
18-10-17在6:22

我认为没有人可以回答。您必须在上下文中显示它。可能是一个单独的问题?

– CygnusX1
18-10-17在12:55

#5 楼

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

d = (a = b, c);


a等于b,而d等于c

评论


几乎正确。语句没有值,表达式没有值。该表达式的值是c。

–莱昂·蒂默曼斯(Leon Timmermans)
08-09-15 at 21:02

为什么用它代替a = b; d = c ;?

–亚伦·弗兰克(Aaron Franke)
18-10-17在6:23

这使我了解到人们在谈论什么副作用。

–鞋带
4月29日,下午2:05

#6 楼

b的值将分配给a。
c不会发生任何变化

#7 楼

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

#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

众所周知,逗号运算符的优先级低于赋值...。 。

评论


因此,第二个示例与仅使i = 1有何不同?在那条线上?

–亚伦·弗兰克(Aaron Franke)
18-10-17在6:23

#8 楼

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

#9 楼

首先,首先要注意的是:逗号实际上不是运算符,对于编译器而言,它只是一个令牌,它在上下文中与其他令牌具有含义。

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

示例1:

要了解不同上下文中相同标记的含义之间的区别,我们来看一个示例:

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


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

上面示例的正确解释当然是它是模板的实例。

示例2:

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

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


逗号的含义取决于u的上下文本身,这就是for构造的上下文。

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

使它更加复杂(与C ++一样)运算符本身可以过载(感谢Konrad Rudolph指出了这一点)。

回到问题所在,代码

a = b, c;


对于编译器而言,意味着类似

(a = b), c;


,因为=令牌/运算符的优先级高于,令牌的优先级。

并且这是在上下文中解释的,例如

a = b;
c;


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

评论


可以,也许我使用了错误的术语(对于词法分析器,这是一个令牌,可以肯定)

– Quonux
13年5月15日在6:23

当与运算符(原文如此)一起使用时,逗号确实是运算符。

–龙主
13年7月11日在1:56

尽管认识到给定的逗号令牌是否被识别为逗号运算符(例如,与参数分隔符相对)可能本身就是一个挑战,但这个问题专门针对逗号运算符。

– CygnusX1
13-10-5在14:08