C - приращение не обновляет значение переменной

Я работаю над простой программой на C, но столкнулся с некоторой путаницей. Ниже приведен код:

int main(void) {
  int i, j, k;
  i = 3;
  j = 4;
  k = 5;

  printf("%d ", i < j || ++j < k);
  printf("\n");  // LINE 1

  printf("%d %d %d", i, j, k);  // LINE 2

  return 0;
}

В приведенной выше программе переменная j начинается с 4. Затем в операторе printf строки 1 мы увеличиваем значение j на 1 (++j = 5).

Итак, теоретически я бы предположил, что когда j печатается в printf (строка 2), оно печатается как 5, поскольку мы сделали приращение в строке 1 для j. Однако каждый раз, когда я запускаю код, строка 2 печатает исходное значение j, которое равно 4, а НЕ 5.

Есть ли что-то, что мне не хватает?


person sye    schedule 25.01.2020    source источник
comment
Почему отрицательные голоса? В вопросе приводится пример кода вместе с ожидаемым результатом и объяснением мыслительного процесса автора.   -  person Joshua Schlichting    schedule 26.01.2020
comment
@JoshuaSchlichting, вероятно, из-за большого количества дубликатов «оценки короткого замыкания»?   -  person Martin James    schedule 26.01.2020
comment
@MartinJames Я просто думаю, что это странно, что люди проголосовали за то, что не знают ответа на свой вопрос. Это выглядит так: если вы не знаете об оценке короткого замыкания, вам лучше не задавать вопрос, где это знание решает проблему, потому что вы должны были знать, что нужно искать вопросы, касающиеся оценки короткого замыкания. Я не думаю, что задавший вопрос знал, что нужно искать эту проблему, поскольку в этом случае он не выглядел подозрительным по отношению к оператору ИЛИ. Им и в голову не пришло проводить исследования по оценке короткого замыкания. Я готов ошибаться в этом...   -  person Joshua Schlichting    schedule 26.01.2020


Ответы (5)


j никогда не увеличивается, потому что ++j никогда не вычисляется. Оператор ИЛИ удовлетворен, когда он сначала проверяет i < j.

person Joshua Schlichting    schedule 25.01.2020
comment
Технически это называется "ленивая оценка". - person JohanC; 26.01.2020

Это пример оценки методом короткого замыкания. Когда логическое выражение равно A || B, если A истинно, нет необходимости вычислять B, и большинство языков придерживаются этого.

В этом случае i ‹ j истинно, поэтому ++j ‹ k игнорируется.

person Michael Rogers    schedule 25.01.2020

Глядя на это выражение:

i < j || ++j < k

Оператор преинкремента ++ имеет наивысший приоритет, за ним следует оператор "меньше чем" <, за которым следует логический оператор ИЛИ ||. Итак, он анализирует так:

(i < j) || ((++j) < k)

Логический оператор ИЛИ || оценивается как истина (в частности, значение 1), если левая или правая сторона оценивается как истина. Из-за этого у него также есть свойство, заключающееся в том, что правая часть не будет оцениваться, если левая сторона оценивается как истина, поскольку результат всего выражения уже известен в этот момент. Это обычно называется краткой оценкой.

Такое поведение продиктовано разделом 6.5.14p3 C стандарт относительно логического оператора ИЛИ:

В отличие от побитового оператора |, оператор || гарантирует вычисление слева направо; если оценивается второй операнд, между оценками первого и второго операндов есть точка последовательности. Если первый операнд не равен 0, второй операнд не оценивается.

Возвращаясь к выражению, сначала вычисляется i < j. Значение i равно 3, а значение j равно 4, поэтому 3 < 4 оценивается как 1. Поскольку это значение левой части оператора ||, результат оператора || равен 1, а правая часть ++j < k не вычисляется. , поэтому j никогда не увеличивается.

person dbush    schedule 26.01.2020

Это называется оценкой короткого замыкания. Если i < j равно true, то ++j < k не будет оцениваться.

person S.S. Anne    schedule 26.01.2020

person    schedule
comment
|| — логическое или, | — побитовое или - person Christian Gibbons; 26.01.2020