Різна поведінка оператора коми у C ++ з поверненням?


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?


Відповіді:


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;є оператором jump ( оператором return ), 2,3є виразом тут.

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


1
гарне пояснення. Але чи є кілька практичних застосувань? або просто помилки, які потрібно зробити?
Жан-Франсуа Фабр

7
@ Jean-FrançoisFabre IMO це просто заплутано, зовсім не корисно.
songyuanyao

11
Я бачив, як один-два рази він використовувався в forциклах, коли, химерно, це може зробити код чіткішим при числових обчисленнях.
Вірсавія

6
@ Jean-FrançoisFabre: як каже Батшеба, це так, щоб ви могли написати щось на зразок i += 1, j += 2у циклі for. Хтось вирішив, що граматика C ++ (точніше граматика C, оскільки ця частина була скопійована звідти) вже досить складна, не намагаючись визначити, що пріоритет коми більше, ніж присвоєння, коли ви пишете, x = 2, 3але нижчий, коли ви пишете x = 2, y = 3!
Steve Jessop

1
@Holger: крапка з комою припиняє оператор, це не оператор. Це те, що відповідь можна змінити, щоб зробити її більш зрозумілою. "x = 2, 3" - вираз із 2 операторами, і з міркувань підтримки for (;;), = має вищий пріоритет. (Як казали всі інші.) Але "поверніть 2, 3;" - це твердження, що містить вираз "2, 3". Існує не технічно черговість до ключового слова «повернення». (Хоча ефективно , оскільки це частина висловлювання, яка приймає вираз, він аналізується в останню чергу - нижчий "пріоритет", ніж будь-який оператор у виразі.)
Micha Berger

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 Так, ти маєш рацію. Я мав на увазі, що я очікував, що мене 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буде повернено лише друге ( ).


2
УФ. Дуже прискіпливий, але було б непогано, якщо б ви позначили <expression>як явно необов’язковий (з граматичної точки зору).
Вірсавія

2
У дереві синтаксичного аналізу є 5 виразів x=2,3. Обидва литералов 2і 3знаходяться в нижній частині дерева синтаксичного аналізу, як це ідентифікатор x. Це все індивідуально допустимі вирази. Оператор пріоритет означає , що =відбувається нижче в дереві розбору, і об'єднує в собі два вирази xі 2в четверте вираз x=2. Нарешті, п’ятий вираз утворюється оператором коми, що з’єднує його дві сторони x=2і 3. Однак ви неправильно заявляєте, що пріоритет оператора визначає порядок оцінки. Це не так. Порядок оцінки визначається правилами послідовності.
MSalters

2
Я проголосував за згадку, що повернення не є частиною виразу
Даніель Жур,

@MSalters Я з вами згоден, але я просто неправильно вжив слово " тому що ", а не " оскільки ". Щось моя англійська мова не така досконала! ; - =
Biagio Festa

2
Чи є тут "макровираз" технічним терміном? Здається, це трохи заплутано використовувати його, коли також існують "макровирази" у значенні матеріалів препроцесора.
сеншин

2

Спробуйте застосувати спрощений підхід, просто виділивши перевагу в дужках:

( x = 2 ), 3;

return ( 2, 3 );

Тепер ми можемо бачити двійковий оператор "," працює однаково на обох, зліва направо.


1
Хитра частина усвідомлює, що x = 2, 3це саме є виразом, тоді як для returnнього return <expression>. Отже, ви читаєте їх як (x = 2, 3)і (2, 3).
xyz
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.