[英]How does the Comma Operator work
逗號運算符在 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;
請注意逗號運算符可能在 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");
逗號運算符在所有 C/C++ 運算符中的優先級最低。 因此,它始終是綁定到表達式的最后一個,這意味着:
a = b, c;
相當於:
(a = b), c;
另一個有趣的事實是逗號運算符引入了一個序列點。 這意味着表達式:
a+b, c(), d
保證按順序計算其三個子表達式( a+b 、 c()和d )。 如果它們有副作用,這很重要。 通常允許編譯器以他們認為合適的任何順序來評估子表達式。 例如,在函數調用中:
someFunc(arg1, arg2, arg3)
可以按任意順序評估參數。 請注意,函數調用中的逗號不是運算符; 它們是分隔符。
它將等於b
。
逗號運算符的優先級低於賦值。
逗號運算符:
為所有類型(內置和自定義)定義了逗號運算符的默認版本,它的工作方式如下 - 給定exprA , exprB
:
exprA
被評估exprA
的結果被忽略exprB
被評估exprB
的結果作為整個表達式的結果返回對於大多數操作符,允許編譯器選擇執行順序,甚至在不影響最終結果的情況下甚至需要跳過執行(例如false && foo()
將跳過對foo
的調用)。 但是,逗號運算符並非如此,上述步驟將始終發生* 。
在實踐中,默認逗號運算符的工作方式幾乎與分號相同。 不同之處在於,用分號分隔的兩個表達式形成兩個單獨的語句,而逗號分隔將所有表達式保留為一個表達式。 這就是為什么有時會在以下場景中使用逗號運算符的原因:
if( HERE )
for
循環的初始化中for ( HERE ; ; )
if (foo) HERE ;
(請不要那樣做,真的很丑!)當語句不是表達式時,分號不能用逗號代替。 例如,這些是不允許的:
(foo, if (foo) bar)
( if
不是表達式)在您的情況下,我們有:
a=b, c;
, 等價於a=b; c;
a=b; c;
,假設a
的類型不會重載逗號運算符。a = b, c = d;
相當於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
a
的值為b
,但表達式的值為c
。 也就是說,在
d = (a = b, c);
a
等於b
, d
等於c
。
b 的值將分配給 a。 c 什么都不會發生
是 逗號運算符的優先級低於賦值運算符
#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
正如我們所知,逗號運算符的優先級低於賦值......
a 的值將等於 b,因為逗號運算符的優先級低於賦值運算符。
首先要做的事情:逗號實際上不是運算符,對於編譯器來說,它只是一個標記,它在與其他標記的上下文中獲得意義。
示例 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;
因為=
令牌/運算符的 優先級高於,
令牌的優先級。
這在上下文中被解釋為
a = b;
c;
(請注意,解釋取決於上下文,這里它既不是函數/方法調用也不是模板實例化。)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.