Как решить постфиксный и префиксный оператор выражения?

Я написал следующий код:

int main(){

int i=-1,j=-1,k=0,l=2,m;
m = i++ && j++ && k++ || l++;
printf("%d %d %d %d %d",i,j,k,l,m);

i=-1,j=-1,k=0,l=2,m;
m = ++i && ++j && ++k || ++l;
printf("\n%d %d %d %d %d",i,j,k,l,m);
    return(0);
}

и я получил следующий результат:

    0 0 1 3 1

    0 -1 0 3 1

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

     i++ && j++ 

должно быть равно

      ++i && ++j 

и оба должны быть эквивалентны

     i && j;
     i = i+1;
     j = j+1;

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

2 ответа

Решение

i++ && j++ определенно не эквивалентно ++i && ++j,

Возьмите случай, когда оба равны нулю - первый результат:

0 && j++

результат 0 (а из-за короткого замыкания j даже не будет увеличен).

Во втором случае вы получите

1 && 1

дает 1 результат.

Имея это в виду, давайте рассмотрим ваши примеры (для удобства чтения добавлены пробелы, точки с запятой и символы новой строки):

  1. Сначала:

    int i = -1;
    int j = -1;
    int k =  0;
    int l =  2;
    int m = i++ && j++ && k++ || l++;
    

    Давайте сначала заключим в скобки полностью, чтобы было легче иметь дело с:

    int m = ((i++ && j++) && k++) || l++;
    

    Итак, что произойдет? Во-первых, i++, i увеличивается (и становится 0), но поскольку это постинкремент, результат выражения -1, Это дает:

    int m = ((-1 && j++) && k++) || l++;
    

    Так как левая сторона этого && не ноль, правая сторона оценивается. j++ приращений j в 0но, опять же, постинкремент означает, что значение выражения -1,

    int m = ((-1 && -1) && k++) || l++;
    

    Разрешите это &&:

    int m = (1 && k++) || l++;
    

    Далее правая сторона оставшихся &&, k увеличивается, становясь 1, но выражение дает 0:

    int m = (1 && 0) || l++;
    

    Разрешите это &&:

    int m = 0 || l++;
    

    И, наконец, потому что левая сторона || 0, правая сторона оценивается. l увеличивается, становясь 3, но как постинкремент, дает 2:

    int m = 0 || 3;
    

    В заключение:

    int m = 1;
    

    И по пути мы закончили с:

    i = 0;
    j = 0;
    k = 1;
    l = 3;
    

    Объясняя свою первую распечатку.

  2. Далее, давайте посмотрим на второй пример (более сжатый; дайте мне знать, если вы хотите больше подробностей):

    int i = -1, j = -1, k = 0, l = 2, m;
    m = ((++i && ++j) && ++k) || ++l;   // parenthesized for readability
           ^                            // i is pre-incremented
    m = (( 0  && ++j) && ++k) || ++l;
               ^                        // first && operator short-circuits
    m = (0 && ++k) || ++l;
            ^                           // second && operator short-circuits
    m = 0 || ++l;
              ^                         // l is pre-incremented
    m = 0 || 3;
           ^                            // evaluate || operator
    m = 1;
    

    Результаты:

    i =  0
    j = -1
    k =  0
    l =  3
    m =  1
    

    Именно то, что вы видели, распечатано.

Проблема в вашем условном операторе:

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

Программа начнет проверку условного оператора (i++ && j++), который равен (-1 && -1), который получается истинным, поэтому он продолжает оператор (true && k++), что означает (true && 0), который является ложным. Затем он проверит условие OR (false || l++), что означает (false || 2). Каждый раз, когда он обрабатывал условия, значения увеличивались с помощью оператора ++.

Второе утверждение, однако...

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

Программа запустила условное условие (++i && ++j), которое равно (0 && ++j). Поэтому он сразу увидел первое условие ++ i как ложное и сразу расценил остальную часть блока (m=++i&&++j&&++k) как ложное, никогда не обрабатывая ++ j или ++ k, как это делал Не нужно, чтобы определить, что блок собирается выйти из строя. Затем он переходит к условию ИЛИ (false || ++l) или (false || 3), что верно, m=1.

В конце концов, второе утверждение только когда-либо обрабатывает ++ i и ++ l, оставляя остальные без изменений.

Я бы немного исследовал что-то под названием "короткое замыкание", так как именно этот термин описывает, почему это происходит.

Другие вопросы по тегам