Прочитав этот ответ о неопределенном поведении и точках последовательности, я написал небольшую программу:
#include <stdio.h>
int main(void) {
int i = 5;
i = (i, ++i, 1) + 1;
printf("%d\n", i);
return 0;
}
Выход есть 2
. О Боже, я не видел приближающегося декремента! Что здесь происходит?
Кроме того, во время компиляции приведенного выше кода я получил предупреждение:
px.c: 5: 8: предупреждение: левый операнд выражения запятой не действует
[-Wunused-value] i = (i, ++i, 1) + 1; ^
Зачем? Но, вероятно, на него автоматически ответит ответ на мой первый вопрос.
printf("2\n");
Ответы:
В выражении
(i, ++i, 1)
запятая используется оператор запятойПоскольку он отбрасывает свой первый операнд, он обычно полезен только тогда, когда первый операнд имеет желательные побочные эффекты . Если побочный эффект первого операнда не имеет места, тогда компилятор может сгенерировать предупреждение о выражении без эффекта.
Таким образом, в приведенном выше выражении
i
будет оцениваться крайнее левое значение, а его значение будет отброшено. Затем++i
будет оцениваться и будет увеличиватьсяi
на 1, и снова значение выражения++i
будет отброшено, но побочный эффектi
является постоянным . Тогда1
будет оцениваться и значение выражения будет1
.Это эквивалентно
Обратите внимание, что вышеприведенное выражение является совершенно допустимым и не вызывает неопределенного поведения, потому что существует точка последовательности между вычислением левого и правого операндов оператора запятой.
источник
i
инициализируется с5
. Посмотрите на заявление декларацииint i = 5;
.++i
, это выражение будет оценено,i
будет увеличено, и это увеличенное значение будет значением выражения. В случаеi++
, если это выражение будет оценено, старое значениеi
будет значением выражения,i
будет увеличено в любой момент между предыдущей и следующей точкой последовательности выражения.Цитирование из
C11
главы6.5.17
, оператор запятойИтак, в вашем случае,
оценивается как
i
, оценивается как пустое выражение, значение отбрасывается++i
, оценивается как пустое выражение, значение отбрасывается1
возвращаемое значение.Итак, окончательное утверждение выглядит так
и
i
добирается до2
. Я думаю, это отвечает на оба ваших вопроса,i
получить значение 2?Примечание: FWIW, так как есть точка последовательность присутствует после оценки левой руки операнда, выражение типа
(i, ++i, 1)
не Invoke UB, так как один может вообще думать по ошибке.источник
i
явно не имеет никакого эффекта! Тем не менее, я не думаю, что это было так очевидно для парня, который не знает оператора запятой (и я не знал, как искать помощь, кроме как задать вопрос). Жаль, я получил так много отрицательных голосов! Я проверю другие ответы и затем решу, что принять. Спасибо! Хороший топ-ответ, кстати.Давайте проанализируем это шаг за шагом.
Итак, мы получаем 2. И окончательное назначение сейчас:
Что бы ни было во мне раньше, оно сейчас перезаписывается.
источник
++i
это не способствует результату.int i = 0; for( ;(++i, i<max); )
Исход
является
Для
оценка происходит так, что
,
оператор отбрасывает оцененное значение и сохраняет только самое правильное значение, которое1
Так
источник
На вики-странице вы найдете полезные материалы для оператора запятой .
В основном это
Это означает, что
будет, в свою очередь, оценивать
i
, отбрасывать результат, оцениватьi++
, отбрасывать результат, а затем оценивать и возвращать1
.источник
(void)exp; a= exp2;
пока мне просто нужноa = exp, exp2;
)Вы должны знать, что делает оператор запятой здесь:
Ваше выражение:
Первое выражение,
i
оценивается, второе выражение,++i
оценивается, и третье выражение,1
возвращается для всего выражения.Таким образом , результат:
i = 1 + 1
.На ваш бонусный вопрос, как вы видите, первое выражение не
i
имеет никакого эффекта, поэтому компилятор жалуется.источник
Запятая имеет «обратный» приоритет. Это то, что вы получите из старых книг и руководств C от IBM (70-е / 80-е). Поэтому последняя «команда» - это то, что используется в родительском выражении.
В современном C его использование странно, но очень интересно в старом C (ANSI):
В то время как все операции (функции) вызываются слева направо, в результате будет использоваться только последнее выражение для условного 'while'. Это предотвращает обработку 'goto's', чтобы сохранить уникальный блок команд для запуска перед проверкой состояния.
РЕДАКТИРОВАТЬ: Это также позволяет избежать вызова функции обработки, которая может позаботиться о всей логике в левых операндах и таким образом вернуть логический результат. Помните, что у нас не было встроенной функции в прошлом C. Таким образом, это могло избежать издержек вызова.
источник