簡體   English   中英

逗號運算符如何工作

[英]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+bc()d )。 如果它們有副作用,這很重要。 通常允許編譯器以他們認為合適的任何順序來評估子表達式。 例如,在函數調用中:

someFunc(arg1, arg2, arg3)

可以按任意順序評估參數。 請注意,函數調用中的逗號不是運算符; 它們是分隔符。

它將等於b

逗號運算符的優先級低於賦值。

逗號運算符:

  • 具有最低優先級
  • 是左結合的

為所有類型(內置和自定義)定義了逗號運算符的默認版本,它的工作方式如下 - 給定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=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) --- 逗號分隔的參數列表。 事實上, 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

a的值為b ,但表達式的值為c 也就是說,在

d = (a = b, c);

a等於bd等於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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM