Операторы C и приоритет

Я использую язык C для кода ниже:

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int num1=0;

    int res = ++num1 && num1++;

    printf("%d\t%d\n",num1,res);    
}

В приведенном выше коде я получаю вывод как 2 1. Я думаю, что вывод должен быть 2 0.

Пожалуйста, поправьте меня, если я ошибаюсь, чтобы решить эту инструкцию, num1++(0) будет выполняться сначала из-за наивысшего приоритета, затем будет выполняться ++num1(2), а затем, наконец, && будет предварительно сформирован, потому что он имеет самый низкий приоритет.

Пожалуйста, прокомментируйте, как выполняется это утверждение.

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


person narayan rathod    schedule 18.12.2020    source источник
comment
&& создает точку последовательности. Из Википедии гарантируется, что все побочные эффекты предыдущих оценок будут выполнены, и никаких побочных эффектов от последующих оценок еще не наблюдалось. Оценка идет слева направо.   -  person Weather Vane    schedule 18.12.2020
comment
Даже если бы вторая часть num1++ была (как вы предполагали) вычислена первой, она бы оценивалась как 0, и правило короткого замыкания говорило бы об этом, потому что все выражение не может быть true , другая (первая) часть не оценивается, поэтому num1 не может быть 2, как вы предполагаете.   -  person Weather Vane    schedule 18.12.2020


Ответы (3)


Здесь много заблуждений. Во-первых, приоритет операций устанавливает порядок анализа, а не порядок выполнения. Есть два связанных, но разных термина: приоритет оператора и порядок оценки.
См. В чем разница между приоритетом оператора и порядком оценки?.

Как только вы поймете порядок вычислений, оператор && будет иметь четко определенную последовательность, которая обычно не имеет место для операторов C. Это гарантирует порядок оценки слева направо. С17 6.5.14/4:

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

Обычно вы не сможете делать дикие и сумасшедшие вещи с оператором ++, смешанным с другими операторами, но приведенное выше правило && делает это возможным в этом конкретном случае.

См. Почему мы не можем смешивать операторы приращения, такие как i++, с другими операторами? Здесь объясняется последовательность/последовательность точки.


В некоторых учебниках я обнаружил, что постфикс ++ и префикс ++ имеют одинаковый приоритет,

Это не так, префикс ++ имеет приоритет над постфиксом (и другими унарными операторами). Так что ассоциативность не применяется.

person Lundin    schedule 18.12.2020

В выражении, используемом в качестве инициализатора

 int res = ++num1 && num1++;

есть точка следования для оператора &&.

Из стандарта C (6.5.13 Логический оператор И)

3 Оператор && должен возвращать 1, если оба его операнда не равны 0; в противном случае возвращается 0. Результат имеет тип int.

а также

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

Сначала оценивается левый операнд оператора, и в результате num1 будет равно 1 из-за унарного (префиксного) оператора приращения. Поскольку подвыражение не равно 0, вычисляется второй операнд. Его значением является значение до увеличения, равное 1. Поскольку этот второй операнд также не равен 0, тогда все выражение оценивается как логическое истинное, и его значение равно 1 (см. первую цитату из стандарта C).

Это значение 1 присваивается переменной res, а переменная num1 после приращения постфикса будет равна 2.

Таким образом, вы получите, что после этого объявления res равно 1, а num1 равно 2.

person Vlad from Moscow    schedule 18.12.2020

Пожалуйста, поправьте меня, если я ошибаюсь, чтобы решить эту инструкцию, num1++(0) будет выполняться сначала из-за наивысшего приоритета, затем будет выполняться ++num1(2), а затем, наконец, && будет предварительно сформирован, потому что он имеет самый низкий приоритет.

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

Все операторы &&, ||, ?: и запятая принудительно оценивают слева направо - левый операнд полностью оценивается (и применяются любые побочные эффекты) перед правым операндом. && и || оба короткое замыкание - для && правый операнд будет оцениваться, только если левый операнд не равен нулю.

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

Результатом выражения && является 1, если оба операнда отличны от нуля, и 0 в противном случае.

Это примерно эквивалентно написанию

tmp = num1 + 1;
num1 = num1 + 1;

res = 0;
if ( tmp != 0 )
{
  if ( num1 != 0 )
  {
    res = 1;
  }
}
num1 = num1 + 1;

Таким образом, результат ++num1 && num1++ равен 1, а значение, хранящееся в num1 в конце, равно 2.

В некоторых учебниках я обнаружил, что постфикс ++ и префикс ++ имеют одинаковый приоритет,

Это крайне неправильно, и вам следует немедленно прекратить использование этих руководств. Постфиксные операторы имеют более высокий приоритет, чем унарные операторы — *a++ анализируется как *(a++), ++a[i] анализируется как ++(a[i]) и т. д. Выражение, подобное ++i++, будет анализироваться как ++(i++), но вы не можете написать такое выражение на C — результат i++ не 'не является lvalue и не может быть операндом такого унарного ++.

person John Bode    schedule 18.12.2020