Другое поведение оператора запятой в с ++ с возвратом?

83

Это (обратите внимание на оператор запятой ):

#include <iostream>
int main() {
    int x;
    x = 2, 3;
    std::cout << x << "\n";
    return 0;
}

выходы 2 .

Однако, если вы используете returnоператор запятой, это:

#include <iostream>
int f() { return 2, 3; }
int main() {
    int x;
    x = f();
    std::cout << x << "\n";
    return 0;
}

Выходы 3 .

Почему оператор запятой ведет себя иначе с return?

xyz
источник

Ответы:

140

В соответствии с приоритетом оператора , оператор запятой имеет более низкий приоритет, чем operator=, поэтому x = 2,3;эквивалентен (x = 2),3;. (Приоритет оператора определяет, как оператор будет привязан к своим аргументам, более жестко или менее жестко, чем другие операторы, в соответствии с их приоритетами.)

Обратите внимание, что выражение запятой (x = 2),3здесь, а не 2,3. x = 2сначала оценивается (и его побочные эффекты завершаются), затем результат отбрасывается, затем 3оценивается (фактически ничего не делает). Вот почему значение xесть 2. Обратите внимание, что 3это результат всего выражения запятой (т.е. x = 2,3), он не будет использоваться для присвоения x. (Измените его на x = (2,3);, xбудет назначено с 3.)

Для получения return 2,3;, выражение запятой 2,3, 2вычисляются затем его результат отбрасывается, а затем 3вычисляется и возвращаются как результат всего выражения запятой, который возвращается в обратном заявлении позже.


Дополнительная информация о выражениях и утверждениях

Выражение - это последовательность операторов и их операндов, определяющая вычисление.

x = 2,3;это выражение выражение , x = 2,3это выражение здесь.

Выражение, за которым следует точка с запятой, является утверждением.

Синтаксис: attr(optional) expression(optional) ; (1)

return 2,3;это оператор перехода ( оператор возврата ), 2,3это выражение здесь.

Синтаксис: attr(optional) return expression(optional) ; (1)

Songyuanyao
источник
1
хорошее объяснение. Но есть ли практические приложения? или просто ошибки делать?
Жан-Франсуа Фабр
7
@ Jean-FrançoisFabre ИМО, это просто сбивает с толку, совсем бесполезно.
songyuanyao
11
Я видел, как он один или два раза использовался в forциклах, когда, как ни странно, он может сделать код более понятным при численных вычислениях.
Вирсавия
6
@ Jean-FrançoisFabre: как говорит Батешеба, это для того, чтобы вы могли написать что-то вроде i += 1, j += 2цикла for. Кто-то решил, что грамматика C ++ (или, скорее, грамматика C, поскольку эта часть была скопирована оттуда) уже достаточно сложна, не пытаясь определить, что приоритет запятой выше, чем присваивание, когда вы пишете, x = 2, 3но ниже, когда вы пишете x = 2, y = 3!
Стив Джессоп
1
@Holger: точка с запятой завершает оператор, это не оператор. Это то, что можно исправить, чтобы сделать более ясным. «x = 2, 3» - это выражение с двумя операторами, и по причинам поддержки (;;) = имеет более высокий приоритет. (Как говорили все.) Но «верните 2, 3;» это утверждение, которое содержит выражение «2, 3». Технически ключевому слову «return» не существует приоритета. (Хотя фактически , поскольку это часть оператора, который принимает выражение, оно анализируется последним - более низкий «приоритет», чем любой оператор в выражении.)
Мика Бергер
32

Оператор запятой (также известный как разделение выражений ) оценивается слева направо. Так return 2,3;эквивалентно return 3;.

Оценка x = 2,3;происходит (x = 2), 3;из-за приоритета оператора . Оценка по-прежнему выполняется слева направо, и все выражение имеет значение 3 с побочным эффектом xпринятия значения 2.

Вирсавия
источник
2
Не могли бы вы отредактировать и уточнить оператор разделения выражений ? Как я уже упоминал в комментарии к ответу @ songyuanyao, я могу понять, почему return 2,3и return (2,3)они такие же. Я считал, что первое должно быть (return 2),3.
xyz
@BiagioFesta хорошо объясняет эту часть.
Вирсавия
1
@ prakharsingh95 return 2- это утверждение (например, сформированное for,while,if), а не выражение. Вы не можете написать, например, f(return 2)или 2+return 2. Итак, (return 2),3синтаксически неверно.
chi
@chi Да, вы правы. Я имел в виду, что ожидал, return 2, 3что меня интерпретируют как (return 2), 3.
xyz
2
@ prakharsingh95 согласно грамматике C ++ returnможет встречаться только в следующих случаях: (a) return expression_opt ; и (b) return braced-init-list ; .
MM
20

Это утверждение:

  x = 2,3;

состоит из двух выражений :

> x = 2
> 3

Так как приоритет операторов , =имеет больший приоритет , чем запятая ,, поэтому x = 2вычисляются и после 3 . Тогда xбудет равно 2.


В returnвместо:

int f(){ return 2,3; }

Синтаксис языка:

return <expression>

Примечание return не является частью выражения.

Таким образом, в этом случае будут оцениваться два выражения:

> 2
> 3

Но 3будет возвращен только второй ( ).

Biagio Festa
источник
2
UV'd. Очень придирчиво, но было бы неплохо, если бы вы пометили его <expression>как явно необязательный (с точки зрения грамматики).
Вирсавия
2
В дереве синтаксического анализа 5 выражений x=2,3. Оба литерала 2и 3находятся внизу дерева синтаксического анализа, как и идентификатор x. Это все индивидуально допустимые выражения. Оператор приоритет означает , что =происходит ниже в дереве разбора, и объединяет в себе два выражения xи 2в четвертое выражение x=2. Наконец, пятое выражение образовано оператором запятой, соединяющим его две стороны x=2и 3. Однако вы неправильно указываете, что приоритет оператора определяет порядок оценки. Это не так. Порядок оценки определяется правилами последовательности.
MSalters
2
Я проголосовал за упоминание о том, что возвращение не является частью выражения,
Даниэль Джур
@MSalters Я согласен с вами, но я просто неправильно использовал слово « потому что » вместо « с тех пор ». Что-то мой английский не так совершенен! ; - =
Biagio Festa
2
Является ли здесь «макровыражение» техническим термином? Кажется немного запутанным использовать его, когда также существуют «макро-выражения» в смысле препроцессора.
senshin 08
2

Попробуйте применить упрощенный подход, просто выделив приоритет круглыми скобками:

( x = 2 ), 3;

return ( 2, 3 );

Теперь мы можем видеть, что бинарный оператор "" работает одинаково в обоих случаях, слева направо.

Лучано
источник
1
Сложная часть - понять, что x = 2, 3это само по себе выражение, а для returnнего return <expression>. Вы читаете их как (x = 2, 3)и (2, 3).
xyz