Оценка логических выражений, содержащих приращение в C - PullRequest
2 голосов
/ 21 марта 2020

Я только что написал небольшую программу, которая поможет мне ознакомиться с логическим выражением в C, и я ожидал, что результат будет:

1 
1 1 1
#include <stdio.h>

int main(void) 

{

    int I = 1, J = 1, K = 1;
    printf("%d\n", ++I || ++J && ++K);
    printf("%d %d %d", I, J ,K);

    return 0;
}

Вместо этого я получил:

1 
2 1 1

Значение I было увеличено на 1, и я понятия не имею, почему.

Насколько я понял, I не было назначено (=) какого-либо нового значения в моей программе, так как же это значение было изменено?

Ответы [ 3 ]

4 голосов
/ 21 марта 2020

Ваш вопрос касается двух отдельных вопросов.

Первый: почему I увеличивается?

Второй: Если вывод 2 1 1 и I был увеличен, почему не J и K затем тоже увеличивается?


1.

Почему увеличивается I?

++ является оператором приращения. Он увеличивает операнд на число 1, аналогично выражениям i = i + 1 или i += 1, где i обозначает операнд.

Существует разница между набором ++ перед (++i) или позади (i++) операнда. Ответы на следующий связанный вопрос касаются разницы в лучшем виде, поэтому я не буду go слишком подробно описывать эту топи c здесь, поскольку различие не является критически важным для предоставленного вами кода, и я просто хотел аннотировать то обстоятельство, что вы правильно используете оператор приращения в ваших будущих программах и избегаете дальнейших путаницы.

C: В чем разница между ++ i и i ++?

Вернуться к вашему коду.

Поскольку вы используете:

printf("%d\n", ++I || ++J && ++K);

I сразу увеличивается на 1 внутри выражения, поэтому его значение на самом деле 2, хотя это не влияет на логическую оценку, потому что любое значение, отличное от нуля, будет оценено как 1 / true в результате теста логического условия.

Именно поэтому

printf("%d %d %d", I, J ,K);

печатает 2 как значение I.


2.

Почему тогда значения J и K тоже не увеличиваются?

Логическое тестирование Ева luates слева направо. && имеет более высокий приоритет, чем ||. && комбинированные выражения / подусловия должны выполняться вместе, чтобы быть оцененными как true условие. Как только условие становится true, как в случае ++I, оценка оставшихся условий опускается, поскольку она является избыточной.

Именно поэтому J и K aren Не увеличивается на 1 с:

printf("%d\n", ++I || ++J && ++K);

, но I равно.

Таким образом, правильный вывод

printf("%d %d %d", I, J ,K);

равен:

2 1 1
2 голосов
/ 21 марта 2020

Глядя на выражение

printf("%d\n", ++I || ++J && ++K);

++I || ++J && ++K - это логическое выражение, да, но оно также увеличивает все переменные, поэтому все они должны быть 2 в конце выражения, а ваш вывод должен быть:

1 // true expression, I, J and K are all positive values
2 2 2

Так почему же этого не происходит?

Ну, так как I = 1, больше никаких вычислений не требуется, потому что компилятор знает, что 1 || 0 && 0 равно 1, (обратите внимание, что оценка слева направо и && имеет приоритет над ||), поэтому ++J и ++K не оцениваются и, следовательно, не увеличиваются.

во втором printf у вас будет I = 2, J = 1 и K = 1.

1 голос
/ 21 марта 2020

Выражение ++I оценивает текущее значение I plus 1; как побочный эффект , I увеличивается.

Из-за правил приоритета оператора выражение ++I || ++J && ++K анализируется как ++I || (++J && ++K). И ||, и && приводят к принудительной оценке слева направо, поэтому ++I вычисляется первым.

Оба || и && короткое замыкание - если левый операнд ++I || ++J && ++K (++I) не равен нулю, тогда результат выражения равен true (1) независимо от значения правого операнда (++J && ++K), поэтому правый операнд не оценивается вообще.

Если I начинается как -1, тогда ++I будет оцениваться в 0 (ложь), а затем ++J && ++K будет оцениваться. Если левый операнд ++J оценивается как 0 (false), то результатом выражения будет false независимо от результата ++K, поэтому ++K не будет оцениваться.

...