Как работает оператор запятой
Как работает оператор запятой в 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
,
Да Оператор запятой имеет меньший приоритет, чем оператор присваивания
#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;
(обратите внимание, что интерпретация зависит от контекста, здесь она не является ни вызовом функции / метода, ни созданием шаблона.)