Порядок оценки выражения - PullRequest
4 голосов
/ 01 октября 2011

Я только что прочитал, что порядок вычисления и приоритет операторов - это разные, но связанные понятия в C ++.Но мне все еще непонятно, как они отличаются, но связаны между собой?например, когда я говорю (c + a) меняю ли я порядок вычисления выражения, меняя его приоритет?

Ответы [ 6 ]

8 голосов
/ 01 октября 2011

Важной частью порядка оценки является наличие каких-либо компонентов с побочными эффектами.

Предположим, у вас есть это:

int i = c() + a() * b();

Где a и b имеют побочные эффекты:

int global = 1;

int a() {
    return global++;
}
int b() {
    return ++global;
}
int c() {
    return global * 2;
}

Компилятор может выбрать, в каком порядке вызывать a(), b() и c(), а затем вставить результаты в выражение. В этот момент приоритет вступает во владение и решает, в каком порядке применять операторы + и *.

В этом примере наиболее вероятными исходами являются либо

  1. Компилятор сначала оценит c(), затем a(), а затем b(), в результате чего i = 2 + 1 * 3 = 5
  2. Сначала компилятор оценивает b(), затем a(), а затем c(), что приводит к i = 6 + 2 * 2 = 10

Но компилятор может свободно выбирать любой порядок, в котором он хочет.

Короткий рассказ состоит в том, что приоритет сообщает вам порядок, в котором операторы применяются к аргументам (* до +), тогда как порядок вычисления говорит вам о том, что порядок разрешения аргументов (a(), b(), c()). Вот почему они «разные, но связаны».

3 голосов
/ 01 октября 2011

«Порядок вычисления» означает, что различные подвыражения в одном и том же выражении оцениваются относительно друг друга.

Например, в

3 * f(x) + 2 * g(x, y)

у вас есть обычные правила приоритета между умножением и сложением. Но у нас есть вопрос оценки порядка: произойдет ли первое умножение перед вторым или второе перед первым? Это важно, потому что если f () имеет побочный эффект, который изменяет y, результат всего выражения будет отличаться в зависимости от порядка операций.

В вашем конкретном примере этот сценарий оценки порядка (в котором результирующее значение зависит от порядка) не возникает.

1 голос
/ 01 октября 2011

Пока мы говорим о встроенных операторах: нет, вы не меняете порядок оценки с помощью (). Вы не можете контролировать порядок оценки. На самом деле здесь нет «порядка оценки».

Компилятору разрешается оценивать это выражение любым способом, который ему нужен, при условии, что результат верен. Даже не требуется использовать операции сложения и умножения для оценки этих выражений. Сложение и умножение существуют только в тексте вашей программы. Компилятор может полностью и полностью игнорировать эти конкретные операции. На некоторой аппаратной платформе такие выражения могут оцениваться по одной атомарной машинной операции. По этой причине понятие «порядок оценки» здесь не имеет никакого смысла. Там нет ничего, к чему вы можете применить понятие «заказ».

Единственное, что вы меняете, используя (), - это математическое значение выражения. Допустим, a, b и c - все 2. a + b * c должно быть равно 6, а (a + b) * c должно быть равно 8. Вот и все. Это единственное, что вам гарантировано: что результаты будут правильными. Как эти результаты получены, совершенно неизвестно. Компилятор может использовать абсолютно все, любой метод и любой «порядок оценки», если результаты верны.

Для другого примера, если в вашей программе есть два таких выражения, следующих друг за другом

int x = c + a * b;
int y = (c + a) * b;

компилятор может оценивать их как

int x = c + a * b;
int y = c * b + x - c;

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

Короче говоря, предполагать, что фактическая оценка будет иметь какое-либо существенное сходство с тем, что вы написали в исходном коде вашей программы, в лучшем случае наивно. Несмотря на распространенное мнение, встроенные операторы, как правило, не переводятся в их машинные «аналоги».

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

0 голосов
/ 14 апреля 2013

Я хочу представить ссылку , которую стоит прочесть в связи с этим вопросом.Правила 3 ​​и 4 упоминают о sequence point, еще одной концепции, которую стоит запомнить.

0 голосов
/ 01 октября 2011

Рассмотрим приведенный ниже пример:

#include <limits.h>
#include <stdio.h>
int main(void)
{
    double a = 1 + UINT_MAX + 1.0;
    double b = 1 + 1.0 + UINT_MAX;
    printf("a=%g\n", a);
    printf("b=%g\n", b);
    return 0;
}

Здесь с точки зрения математики, как мы ее знаем, a и b должны вычисляться одинаково и должны иметь одинаковый результат. Но так ли это в мире C (++)? Смотрите вывод программы.

0 голосов
/ 01 октября 2011

Ответ может или не может.

Порядок вычисления a, b и c зависит от интерпретации этой формулы компилятором.

...