逗号运算符如何工作
Posted
技术标签:
【中文标题】逗号运算符如何工作【英文标题】:How does the Comma Operator work 【发布时间】:2010-09-08 10:08:52 【问题描述】:逗号运算符在 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;
【问题讨论】:
在此处了解更多信息。 ***.com/questions/12824378/… What does the comma operator `,` do in C? 的可能重复项。它打败了你一天。而 lillq 的回答提供了关于a = (b, c);
的问题的答案。
但在这种情况下,a = b, c = d;
实际上与预期的a = b; c = d;
执行相同?
@NargothBond 不一定。如果b
和d
是使用(和修改)公共状态的函数评估,则直到C++17
才定义执行顺序。
【参考方案1】:
请注意逗号运算符可能在 C++ 中被重载。因此,实际行为可能与预期大相径庭。
例如,Boost.Spirit 非常巧妙地使用逗号运算符来实现符号表的列表初始值设定项。因此,它使以下语法成为可能且有意义:
keywords = "and", "or", "not", "xor";
请注意,由于运算符优先级,代码(故意!)与
(((keywords = "and"), "or"), "not"), "xor";
也就是说,第一个调用的运算符是keywords.operator =("and")
,它返回一个代理对象,在该对象上调用剩余的operator,
s:
keywords.operator =("and").operator ,("or").operator ,("not").operator ,("xor");
【讨论】:
嗯,你不能改变优先级,这意味着你应该在你的列表周围加上括号。 @Jeff 相反。用括号括住列表,这将不起作用,因为那时编译器只会看到两个char[]
之间的逗号运算符,不能重载。代码有意首先调用operator=
,然后为每个剩余元素调用operator,
。【参考方案2】:
逗号运算符在所有 C/C++ 运算符中具有最低优先级。因此,它始终是绑定到表达式的最后一个,这意味着:
a = b, c;
相当于:
(a = b), c;
另一个有趣的事实是逗号运算符引入了sequence point。这意味着表达式:
a+b, c(), d
保证对其三个子表达式(a+b、c()和d)按顺序进行评估。如果它们有副作用,这很重要。通常允许编译器以他们认为合适的任何顺序来评估子表达式。例如,在函数调用中:
someFunc(arg1, arg2, arg3)
参数可以按任意顺序计算。请注意,函数调用中的逗号是 not 运算符;它们是分隔符。
【讨论】:
值得指出,,
的优先级如此之低,甚至落后于 自身 ;) ...即:逗号作为-运算符 i> 的优先级低于逗号作为分隔符。因此,如果您想在单个函数参数、变量赋值或其他逗号分隔列表中使用逗号作为运算符 - 那么您需要使用括号,例如:int a = 1, b = 2, weirdVariable = (++a, b), d = 4;
【参考方案3】:
等于b
。
逗号运算符的优先级低于赋值。
【讨论】:
【参考方案4】:逗号运算符:
优先级最低 是左关联的为所有类型(内置和自定义)定义了一个默认版本的逗号运算符,它的工作方式如下 - 给定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_operator
【讨论】:
值得注意的是,如果operator ,
被重载,您将失去任何对关联性的保证(就像您失去operator&&
和operator||
的短路属性一样,如果它们被重载) ?
逗号运算符是左关联的,无论它是否重载。表达式a, b, c
总是意味着(a, b), c
而不是a, (b, c)
。如果元素的类型不同,后一种解释甚至可能导致编译错误。您可能追求的是参数的评估顺序?我对此不确定,但也许你是对的:c
可能会在 之前 (a, b)
被评估,即使逗号是左关联的。
只是对类构造函数中逗号分隔的初始化列表的一点评论,顺序不是由列表中的位置决定的。顺序由类的声明位置决定。例如。 struct Foo Foo() : a(5), b(3) int b; int a;
在 a(5)
之前评估 b(3)
。如果您的列表是这样的,这很重要:Foo() : a(5), b(a)
。 b 不会设置为 5,而是 a 的未初始化值,您的编译器可能会或可能不会警告。
我最近遇到了一个有两个浮点数的逗号运算符,评估和丢弃一个数字有什么意义?
我认为没有人能回答这个问题。您必须在上下文中显示它。可能是一个单独的问题?【参考方案5】:
a
的值将是 b
,但 表达式 的值将是 c
。也就是说,在
d = (a = b, c);
a
等于 b
,d
等于 c
。
【讨论】:
几乎正确。语句没有值,表达式有。该表达式的值为 c。 为什么用这个代替a = b; d = c;
?
这让我明白了人们在谈论什么副作用。【参考方案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;
有何不同?【参考方案8】:
a 的值将等于 b,因为逗号运算符的优先级低于赋值运算符。
【讨论】:
【参考方案9】:第一件事:逗号实际上不是运算符,对于编译器来说,它只是一个标记,在上下文中与其他标记一起获得意义。
这是什么意思,为什么要麻烦?
示例 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;
因为=
令牌/运算符的priority高于,
令牌的优先级。
这在上下文中被解释为
a = b;
c;
(请注意,解释取决于上下文,这里它既不是函数/方法调用也不是模板实例化。)
【讨论】:
当然是,也许我使用了错误的术语(对于词法分析器,它是一个标记,当然) 作为一个与 operator, (原文如此)一起工作的人,逗号确实是一个运算符。 虽然识别给定的逗号标记是否被识别为逗号运算符(与例如参数分隔符相反)本身可能是一个挑战,但这个问题专门关于 逗号运算符.以上是关于逗号运算符如何工作的主要内容,如果未能解决你的问题,请参考以下文章