Оператор-запятая

редактировать
(языки программирования C и C ++), результатом которого является выполнение последовательности операций

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

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

Содержание
  • 1 Синтаксис
  • 2 Примеры
  • 3 Использование
    • 3.1 Для циклов
    • 3.2 Макросы
    • 3.3 Условие
    • 3.4 Комплексный возврат
    • 3.5 Избегайте блокировки
  • 4 Другие языки
  • 5 См. Также
  • 6 Ссылки
    • 6.1 Библиография
  • 7 Внешние ссылки
Синтаксис

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

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

Примеры

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

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

Оператор запятой имеет относительно ограниченные варианты использования. Поскольку он отбрасывает свой первый операнд, он обычно полезен только тогда, когда первый операнд имеет желательные побочные эффекты, которые должны быть упорядочены перед вторым операндом. Кроме того, поскольку он редко используется за пределами определенных идиом и легко ошибочно используется с другими запятыми или точкой с запятой, он потенциально сбивает с толку и подвержен ошибкам. Тем не менее, есть определенные обстоятельства, в которых он обычно используется, особенно в циклах for и в SFINAE. Для встроенных систем, которые могут иметь ограниченные возможности отладки, оператор запятой может использоваться в сочетании с макросом, чтобы легко переопределить вызов функции, чтобы вставить код непосредственно перед вызовом функции.

Для циклов

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

void rev (char * s, size_t len) {char * first; for (first = s, s + = len; s>= first; --s) {putchar (* s); }}

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

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

++ p, ++ q; ++ p; ++ q;

Макросы

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

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

#include #include int main (void) {int i; for (i = 0; i <=9; i++) { assert( ( "i is too big!", i <= 4)); printf("i = %i\n", i); } return 0; }

Вывод:

i = 0 i = 1 i = 2 i = 3 i = 4 assert: assert.c: 6: test_assert: Assertion `(" i слишком big! ", i <= 4)' failed. Aborted

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

Условие

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

if (y = f (x), y>x) {... // операторы, включающие x и y}

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

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

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

если (сбой) возврат (errno = EINVAL, -1);

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

if (ошибка) {errno = EINVAL; возврат -1; }

Избегайте блока

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

if (x == 1) y = 2, z = 3; если (x == 1) y = 2, z = 3;

вместо:

if (x == 1) {y = 2; z = 3;} если (x == 1) {y = 2; z = 3; }
Другие языки

В языках программирования OCaml и Ruby для этой цели используется точка с запятой (";"). JavaScript и Perl используют оператор запятой так же, как это делает C / C ++. В Java запятая - это разделитель, используемый для разделения элементов в списке в различных контекстах. Это не оператор и не оценивает последний элемент в списке.

См. Также
Ссылки

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

Внешние ссылки
Последняя правка сделана 2021-05-15 06:43:31
Содержание доступно по лицензии CC BY-SA 3.0 (если не указано иное).
Обратная связь: support@alphapedia.ru
Соглашение
О проекте