У меня есть вопрос о правилах приоритета в C - PullRequest
0 голосов
/ 22 апреля 2020

В следующей функции:

int fun(int *k) {
    *k += 4;
    return 3 * (*k) - 1;
}

void main() {
    int i = 10, j = 10, sum1, sum2;
    sum1 = (i / 2) + fun(&i);
    sum2 = fun(&j) + (j / 2);
}

Вы получите сумму 1, равную 46, и сумму 2, равную 48. Как будет работать функция, если бы не было правил приоритета?

Насколько радикально отличались бы вещи без последовательных правил приоритета?

1 Ответ

0 голосов
/ 22 апреля 2020

Правила предшествования говорят нам, как выражение структурировано , а не как оно оценено . В sum1 = (i / 2) + fun(&i); правила говорят нам следующее:

  • i / 2 сгруппировано, потому что оно в скобках; он не может образовать, например, (sum1 = i) / 2 + fun(&i);.
  • (i / 2) и fun(&i) сгруппированы вместе, потому что + имеет более высокий приоритет, чем =, что делает sum1 = ((i / 2) + fun(&i); вместо (sum1 = (i / 2)) + fun(&i);.

Правила предшествования не говорят нам, оценивается ли сначала i / 2 или fun(&i). На самом деле, ни один из правил в стандарте C не определяет, оценивается ли i / 2 или fun(&i) в первую очередь. Компилятор может выбрать.

Если сначала вычисляется i / 2, результатом будет 10 / 2 + 41, а затем 5 + 41 и, наконец, 46. если сначала вычисляется fun(&i), результатом будет 14 / 2 + 41, а затем 7 + 41 и, наконец, 48. Ваш компилятор выбрал первый. Он мог бы выбрать последнее.

Как бы работала функция, если бы не было правил приоритета?

Если бы не было правил, мы бы не знали, как эта функция будет казнен. Правила - это то, что говорит нам, как это будет выполняться.

Некоторые комментарии утверждают, что поведение этой программы не определено. Это неверно. Это недоразумение исходит из C 2018 6.5 2, в котором говорится:

Если побочный эффект на скалярном объекте не секвенирован относительно другого побочного эффекта на том же скалярном объекте или вычисления значения с использованием значение того же скалярного объекта, поведение не определено…

В вашем коде i / 2 использует i, а fun(&i) содержит «побочный эффект» на i (изменяя его значение через назначение). Если бы они не были упорядочены, поведение было бы неопределенным. Однако после вычисления аргумента в fun и перед его вызовом есть точка последовательности, и после каждого полного выражения в fun есть точки последовательности, включая оператор return. Таким образом, существует некоторая последовательность использования i и побочных эффектов на него. Эта последовательность не полностью определена правилами стандарта C, но она, как определено стандартом, имеет неопределенную последовательность, а не последовательность.

...