题
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;
解决方案
它等于 b
.
逗号运算符的优先级低于赋值运算符。
其他提示
请注意,逗号运算符在 C++ 中可能会重载。因此,实际行为可能与预期有很大不同。
举个例子, 精神振奋 非常巧妙地使用逗号运算符来实现符号表的列表初始值设定项。因此,它使得以下语法成为可能并且有意义:
keywords = "and", "or", "not", "xor";
请注意,由于运算符优先级,代码(故意!)与
(((keywords = "and"), "or"), "not"), "xor";
也就是说,调用的第一个运算符是 keywords.operator =("and")
它返回一个代理对象,剩余的 operator,
s 被调用:
keywords.operator =("and").operator ,("or").operator ,("not").operator ,("xor");
逗号运算符有 最低 所有 C/C++ 运算符的优先级。因此它总是最后一个绑定到表达式的,这意味着:
a = b, c;
相当于:
(a = b), c;
另一个有趣的事实是逗号运算符引入了 序列点. 。这意味着该表达式:
a+b, c(), d
保证有它的三个子表达式 (a+b, C() 和 d)按顺序评估。如果它们有副作用,这一点就很重要了。通常,编译器可以按照他们认为合适的任何顺序来计算子表达式;例如,在函数调用中:
someFunc(arg1, arg2, arg3)
参数可以按任意顺序求值。请注意,函数调用中的逗号是 不是 运营商;他们是分隔符。
逗号运算符:
- 优先级最低
- 是左结合的
为所有类型(内置和自定义)定义了默认版本的逗号运算符,其工作原理如下 - 给定 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) {}
--- 类构造函数中以逗号分隔的初始值设定项列表
* 如果您应用优化,则情况并不完全正确。如果编译器认识到某段代码对其余代码完全没有影响,它将删除不必要的语句。
的价值 a
将 b
, ,但值 表达方式 将 c
. 。也就是说,在
d = (a = b, c);
a 等于 b
, , 和 d
将等于 c
.
b 的值将分配给 a。c什么都不会发生
a 的值将等于 b,因为逗号运算符的优先级低于赋值运算符。
是 逗号运算符的优先级低于赋值运算符
#include<stdio.h>
int main()
{
int i;
i = (1,2,3);
printf("i:%d\n",i);
return 0;
}
输出 :我=3
因为逗号运算符总是返回最右边的值。
如果逗号运算符与赋值运算符一起使用:
int main()
{
int i;
i = 1,2,3;
printf("i:%d\n",i);
return 0;
}
输出:我=1
众所周知,逗号运算符的优先级低于赋值......
首先要做的事情是: 逗号实际上不是一个运算符,对于编译器来说它只是一个具有含义的标记 在上下文中 与其他代币。
这意味着什么以及为什么要这么麻烦?
示例1:
为了理解不同上下文中相同标记的含义之间的差异,我们看一下这个例子:
class Example {
Foo<int, char*> ContentA;
}
通常 C++ 初学者会认为这个表达式可以/会比较事物,但这是绝对错误的, <
, >
和 ,
令牌取决于使用上下文。
对上面例子的正确解释当然是它是模板的实例化。
示例2:
当我们编写一个典型的 for 循环时,它具有多个初始化变量和/或多个表达式,这些表达式应该在循环的每次迭代之后完成,我们也使用逗号:
for(a=5,b=0;a<42;a++,b--)
...
逗号的含义取决于使用上下文,这里是上下文 for
建造。
上下文中的逗号实际上意味着什么?
让事情变得更加复杂(就像在 C++ 中一样),逗号运算符本身可以被重载(感谢 康拉德·鲁道夫 指出这一点)。
回到问题,代码
a = b, c;
对于编译器来说意味着类似
(a = b), c;
因为 优先事项 的 =
令牌/运算符的优先级高于 ,
令牌。
这在上下文中解释为
a = b;
c;
(请注意,解释取决于上下文,这里它既不是函数/方法调用,也不是模板实例化。)