Как работает оператор запятой

Как работает оператор запятой в 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;

9 ответов

Решение

Было бы равно b,

Оператор запятой имеет более низкий приоритет, чем присваивание.

Оператор запятой имеет самый низкий приоритет среди всех операторов C/C++. Поэтому это всегда последний, который связывается с выражением, означая это:

a = b, c;

эквивалентно:

(a = b), c;

Еще один интересный факт заключается в том, что оператор запятой вводит точку последовательности. Это означает, что выражение:

a+b, c(), d

гарантируется, что его три подвыражения (a + b, c () и d) будут оцениваться по порядку. Это важно, если у них есть побочные эффекты. Обычно компиляторам разрешается оценивать подвыражения в любом порядке, который они сочтут нужным; например, в вызове функции:

someFunc(arg1, arg2, arg3)

аргументы могут быть оценены в произвольном порядке. Обратите внимание, что запятые в вызове функции не являются операторами; они являются разделителями.

Обратите внимание, что оператор запятой может быть перегружен в 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");

Оператор запятой:

  • имеет самый низкий приоритет
  • левоассоциативен

Версия оператора запятой по умолчанию определена для всех типов (встроенных и пользовательских) и работает следующим образом. 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

Значение a будет b, но значение выражения будет c, То есть в

d = (a = b, c);

А будет равно b, а также d будет равно c,

Значение b будет присвоено a. Ничего не случится с

Да Оператор запятой имеет меньший приоритет, чем оператор присваивания

#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;
}

Ouput: я =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;

(обратите внимание, что интерпретация зависит от контекста, здесь она не является ни вызовом функции / метода, ни созданием шаблона.)

Другие вопросы по тегам