Оценка экспрессии С - PullRequest
       4

Оценка экспрессии С

6 голосов
/ 12 октября 2010
int main() {
  int i = -3, j = 2,  k = 0, m;
  m = ++i || ++j && ++k;
  printf("%d %d %d %d\n", i, j, k, m);
  return 0;
}

я думал, что && имеет больший приоритет, чем ||согласно этой логике ++j должен выполняться, но он никогда не выполняется, и программа выводит -2 2 0 1.Что здесь происходит?Каковы промежуточные шаги?

Ответы [ 8 ]

14 голосов
/ 12 октября 2010

&& имеет более высокий приоритет, чем ||, что означает, что ++i || ++j && ++k анализируется как ++i || (++j && ++k).

Однако это не меняет того факта, что RHS || выполняется только еслиLHS возвращает 0.

Приоритет не влияет на порядок оценки.

7 голосов
/ 12 октября 2010

Приоритет не влияет на порядок оценки (за исключением случаев, когда это необходимо - некоторые подвыражения могут нуждаться в оценке перед другими из-за приоритета).Например, в простом выражении:

a() + b() + c() * d()

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

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

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

Таким образом, || не только обеспечивает гарантию упорядочения, но и гарантирует, что при определенных условиях второй операнд выигралне может быть вычислено вообще.

(там также указано что-то похожее для && - за исключением того, что в этом случае 2-й операнд не оценивается, если первый оценивается как 0. Но в вашем примере,|| стоит первым).

Другие операторы, обеспечивающие некоторую гарантию упорядочения, включают оператор запятой и вызов функции (которая гарантирует, что аргументы были оценены, но не порядок, в котором эти аргументы были оценены).

4 голосов
/ 12 октября 2010

C ++ использует ленивые вычисления для логических операторов.
Если вы напишите a || b, а a - истина, b никогда не будет оцениваться, поскольку результат будет истинным, даже если b - ложь.
Аналогично, a && b не будет оценивать b, если a равно false.

Поскольку ++i дает истинное значение, ни одно из других выражений не оценивается.

1 голос
/ 12 октября 2010
  1. Оператор || выполняет оценку слева направо, поэтому выражение ++i сначала полностью вычисляется, в результате получается -2.
  2. Оператор || форсирует точку последовательности, поэтому применяется побочный эффект, и i теперь равно -2.
  3. Результат выражения ++i не равен 0, поэтому выражение ++j && ++k вообще не вычисляется.
  4. Поскольку LHS не равен нулю, результатом всего выражения ++i || ++j && ++k будет 1 (true), которое присваивается m.

Просто повторить то, что сказали несколько других, приоритет и порядок оценки - это не одно и то же.

1 голос
/ 12 октября 2010

C делает короткого замыкания логических выражений, поэтому для вычисления ++i достаточно выяснить, что m должно быть истинным.

1 голос
/ 12 октября 2010

&& и || используйте оценку короткого замыкания, то есть в выражении a && b a вычисляется первым, если оно ложно, тогда все выражение ложно и b не оценивается В a || b, если a истинно, то b не оценивается. Обратите внимание, что если вы перегружаете && или || правила короткого замыкания больше не применяются. НТН

0 голосов
/ 12 октября 2010

m = ++ i || ++ j && ++ k;

Так как && имеет более высокий приоритет, чем ||, поэтому выражение интерпретируется как ++i || (++j && ++k)

|| - это короткое замыкание, поэтому правый операнд оператора || не оценивается, поскольку ++i возвращает ненулевое значение.

0 голосов
/ 12 октября 2010

Вы случайно не хотели набрать:

m = ++i | ++j & ++k;

который выводит -2 3 1 -1

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...