Оператор запятой - Comma operator - Wikipedia

в C и C ++ языки программирования, оператор запятой (представлен жетон ,) это бинарный оператор который оценивает свой первый операнд и отбрасывает результат, а затем оценивает второй операнд и возвращает это значение (и тип); Существует точка последовательности между этими оценками.

Использование токена запятой как оператор отличается от его использования в вызовы функций и определения, объявления переменных, объявления перечислений и аналогичные конструкции, где он действует как разделитель.

Синтаксис

Оператор запятой разделяет выражения (которые имеют ценность) аналогично тому, как точка с запятой прекращается заявления, и последовательности выражений заключаются в круглые скобки аналогично тому, как последовательности операторов заключаются в фигурные скобки:[1] (а, б, в) представляет собой последовательность выражений, разделенных запятыми, которая вычисляется до последнего выражения c пока {а; б; c;} представляет собой последовательность операторов и не дает никакого значения. Запятая может стоять только между двумя выражениями - запятыми. отдельный выражения - в отличие от точки с запятой, которая стоит в конце (неблочного) оператора - точки с запятой прекратить заявления.

Оператор запятой имеет самый низкий приоритет любого оператора C и действует как точка последовательности. В комбинации запятых и точек с запятой, точки с запятой имеют более низкий приоритет, чем запятые, поскольку точки с запятой разделяют операторы, но запятые встречаются внутри операторов, что соответствует их использованию в качестве обычной пунктуации: а, б; CD сгруппирован как (а, б); (CD) потому что это два отдельных утверждения.

Примеры

В этом примере различное поведение между второй и третьей строками связано с тем, что оператор запятой имеет более низкий приоритет, чем присваивание. Последний пример также отличается, поскольку возвращаемое выражение должно быть полностью вычислено, прежде чем функция сможет вернуться.

/** * Запятые действуют в этой строке как разделители, а не как оператор. * Результаты: a = 1, b = 2, c = 3, i = 0 */int а=1, б=2, c=3, я=0;/** * Присваивает значение b i. * Запятые действуют как разделители в первой строке и как оператор во второй строке. * Результаты: a = 1, b = 2, c = 3, i = 2 */int а=1, б=2, c=3;              int я = (а, б);                                 /** * Присваивает значение переменной i. * Эквивалентно: int (i = a), b; * Запятые действуют как разделители в обеих строках. * Фигурные скобки во второй строке позволяют избежать повторного объявления переменных в том же блоке, * что могло бы вызвать ошибку компиляции. * Второй объявленный b не имеет начального значения. * Результаты: a = 1, b = 2, c = 3, i = 1 */int а=1, б=2, c=3;                                { int я = а, б; }/** * Увеличивает значение a на 2, затем присваивает значение результирующей операции a + b i. * Запятые действуют как разделители в первой строке и как оператор во второй строке. * Результаты: a = 3, b = 2, c = 3, i = 5 */int а=1, б=2, c=3;int я = (а += 2, а + б);          /** * Увеличивает значение a на 2, затем сохраняет значение a в i и отбрасывает неиспользуемые * значения результирующей операции a + b. * Эквивалентно: ((i = a) + = 2), a + b; * Запятые действуют как разделители в первой строке и как оператор в третьей строке. * Результаты: a = 3, b = 2, c = 3, i = 3 */int а=1, б=2, c=3;int я;я = а += 2, а + б;/** * Присваивает значение i. * Запятые действуют как разделители в обеих строках. * Фигурные скобки во второй строке позволяют избежать повторного объявления переменных в том же блоке, * что могло бы вызвать ошибку компиляции. * Вторые заявленные b и c не имеют начального значения. * Результаты: a = 1, b = 2, c = 3, i = 1 */int а=1, б=2, c=3;{ int я = а, б, c; }/** * Запятые действуют как разделители в первой строке и как оператор во второй строке. * Присваивает значение c переменной i, отбрасывая неиспользуемые значения a и b. * Результаты: a = 1, b = 2, c = 3, i = 3 */int а=1, б=2, c=3;int я = (а, б, c);/** * Возвращает 6, а не 4, поскольку последовательность оператора запятой указывает после ключевого слова  * return считаются одним выражением, оцениваемым как rvalue финального  * подвыражение c = 6. * Запятые в этой строке действуют как операторы. */возвращаться а=4, б=5, c=6;/** * Возвращает 3, а не 1 по той же причине, что и в предыдущем примере. * Запятые в этой строке действуют как операторы. */возвращаться 1, 2, 3;/** * Возвращает 3, а не 1, по той же причине, что и выше. Этот пример работает так же, как и * потому что return - это ключевое слово, а не вызов функции. Хотя компиляторы будут  * разрешить конструкцию return (значение), круглые скобки относятся только к "значению" * и не оказывают особого влияния на ключевое слово return. * Return просто получает выражение, а здесь выражение - «(1), 2, 3». * Запятые в этой строке действуют как операторы. */возвращаться(1), 2, 3;

Использует

Варианты использования оператора запятой относительно ограничены. Поскольку он отбрасывает свой первый операнд, он обычно полезен только там, где первый операнд желателен. побочные эффекты это должно быть последовательность до второй операнд. Кроме того, поскольку он редко используется за пределами определенных идиом и его легко спутать с другими запятыми или точкой с запятой, он потенциально сбивает с толку и подвержен ошибкам. Тем не менее, есть определенные обстоятельства, в которых он обычно используется, особенно в циклах for и в СФИНАЕ.[2] Для встроенных систем, которые могут иметь ограниченные возможности отладки, оператор запятой может использоваться в сочетании с макросом, чтобы легко переопределить вызов функции, чтобы вставить код непосредственно перед вызовом функции.

Для петель

Чаще всего используется для разрешения нескольких назначение операторы без использования оператора блока, в первую очередь в выражениях инициализации и приращения для цикла. Это единственное идиоматическое использование в элементарном программировании на C. В следующем примере важен порядок инициализаторов цикла:

пустота rev(char *s, size_t len){    char *первый;    за (первый = s, s += len; s >= первый; --s) {        путчар(*s);    }}

Альтернативным решением этой проблемы на других языках является параллельное назначение, который позволяет выполнять несколько назначений в одном операторе, а также использует запятую, хотя и с другим синтаксисом и семантикой. Это используется в Идти в аналоге цикла for.[3]

Вне инициализаторов цикла for (которые имеют специальное использование точек с запятой) вместо точки с запятой может использоваться запятая, особенно когда рассматриваемые операторы работают аналогично приращению цикла (например, в конце цикла while):

++п, ++q;++п; ++q;

Макросы

Запятая может использоваться в макросах препроцессора для выполнения нескольких операций в пространстве одного синтаксического выражения.

Одним из распространенных способов использования является предоставление настраиваемых сообщений об ошибках в неудачных утверждениях. Это делается путем передачи списка выражений в скобках в утверждать макрос, где первое выражение - строка ошибки, а второе выражение - утверждаемое условие. В утверждать макрос выводит свой аргумент дословно при неудачном утверждении. Ниже приведен пример:

#включают <stdio.h>#включают <assert.h>int главный ( пустота ){    int я;    за (я=0; я<=9; я++)    {        утверждать( ( "я слишком большой!", я <= 4 ) );        printf("i =% i п", я);    }    возвращаться 0;}

Выход:

i = 0i = 1i = 2i = 3i = 4assert: assert.c: 6: test_assert: Assertion `(« i is too big! », i <= 4) 'не удалось.

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

Условие

Запятая может использоваться в условии (if, while, do while или for), чтобы разрешить вспомогательные вычисления, в частности вызов функции и использование результата, с блокировка:

если (у = ж(Икс), у > Икс) {    ... // операторы с участием x и y}

Подобная идиома существует в Идти, где синтаксис оператора if явно допускает необязательный оператор.[4]

Комплексный возврат

Запятую можно использовать в операторах возврата, чтобы назначить их глобальной переменной или параметру out (передается по ссылке). Эта идиома предполагает, что присваивания являются частью возврата, а не вспомогательными присваиваниями в блоке, который завершается фактическим возвратом. Например, при установке глобального номера ошибки:

если (отказ)    возвращаться (errno = EINVAL, -1);

Более подробно это можно записать как:

если (отказ) {    errno = EINVAL;    возвращаться -1;}

Избегайте блокировки

Для краткости можно использовать запятую, чтобы избежать блока и связанных фигурных скобок, например:

если (Икс == 1) у = 2, z = 3;если (Икс == 1)    у = 2, z = 3;

вместо:

если (Икс == 1) {у = 2; z = 3;}если (Икс == 1) {    у = 2; z = 3;}

Другие языки

в OCaml и Рубин в языках программирования для этого используется точка с запятой («;»). JavaScript[5] и Perl[6] используйте оператор запятой так же, как это делает C / C ++. В Ява, запятая - это разделитель, используемый для разделения элементов в списке в различных контекстах.[7] Это не оператор и не оценивает последний элемент в списке.[8]

Смотрите также

Рекомендации

  1. ^ "Оператор запятой:,". Microsoft документация разработчиков. Архивировано из оригинал (HTML) 1 августа 2019 г.. Получено 1 августа 2019. Два выражения, разделенные запятой, оцениваются слева направо. Левый операнд всегда оценивается, и все побочные эффекты завершаются до того, как оценивается правый операнд.
  2. ^ http://en.cppreference.com/w/cpp/language/sfinae
  3. ^ Эффективный Go: за, "Наконец, в Go нет оператора запятой, а ++ и - являются операторами, а не выражениями. Таким образом, если вы хотите запустить несколько переменных в for, вам следует использовать параллельное присваивание (хотя это исключает ++ и -)."
  4. ^ Спецификация языка программирования Go: Если заявления
  5. ^ «Оператор-запятая». Веб-документы MDN. 17 января 2020. Архивировано с оригинал (HTML) 12 июля 2014 г.. Получено 25 января 2020. Вы можете использовать оператор запятой, если хотите включить несколько выражений в место, для которого требуется одно выражение.
  6. ^ https://perldoc.perl.org/perlop.html#Comma-Operator
  7. ^ «2.4. Грамматические обозначения». Корпорация Oracle. Архивировано из оригинал (HTML) 22 июля 2019 г.. Получено 25 июля 2019.
  8. ^ https://stackoverflow.com/questions/38733508/is-comma-operator-or-separator-in-java

Библиография

  • Рамаджаран, В. (1994), Компьютерное программирование на C, Нью-Дели: Prentice Hall of India
  • Диксит, Дж. Б. (2005), Основы компьютеров и программирования на C, Нью-Дели: Laxmi Publications
  • Керниган, Брайан В .; Ричи, Деннис М. (1988), Язык программирования C (2-е изд.), Englewood Cliffs, NJ: Prentice Hall

внешняя ссылка