Почему этот оператор if, объединяющий присваивание и проверку на равенство, возвращает true? - PullRequest
210 голосов
/ 22 мая 2019

Я думал о некоторых ошибках новичка, и в итоге я обнаружил ошибку в заявлении if. Я немного расширил код до этого:

int i = 0;
if (i = 1 && i == 0) {
    std::cout << i;
}

Я видел, что оператор if возвращает true, и он cout i как 1. Если i назначено 1 в операторе if, почему i == 0 вернул true?

Ответы [ 4 ]

383 голосов
/ 22 мая 2019

Это связано с приоритетом оператора .

if (i = 1 && i == 0)

не

if ((i = 1) && (i == 0))

потому что && и == имеют более высокий приоритет, чем =. То, к чему это действительно работает, является

if (i = (1 && (i == 0)))

, который присваивает результат 1 && (i == 0) i. Так, если i начинается с 0, тогда i == 0 равен true, поэтому 1 && true равен true (или 1), а затем i устанавливается на 1. Тогда, поскольку 1 имеет значение true, вы вводите блок if и печатаете значение, назначенное для i.

14 голосов
/ 22 мая 2019

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

#include <iostream>
using namespace std;

int main()  {
    int i = 0;
    if (i = 1 && i == 0) {
        cout << i;
    }
}

Тогда это:

if (i = 1 && i == 0) {

оценивается как

 if (i = (1 && i == 0)) {

и поэтому i установленодо 1.

0 голосов
/ 28 мая 2019

Фактический ответ:

  1. Компилятор присваивает приоритет значению "i == 0", что дает значение true.
  2. Затем он оцениваетi = 1 как TRUE или FALSE, и поскольку скомпилированные операторы присваивания никогда не завершаются ошибкой (в противном случае они не скомпилируются), оно также оценивается как true.
  3. Поскольку оба оператора оцениваются как true, а TRUE && TRUE оценивается как TRUEоператор if будет иметь значение TRUE.

В качестве доказательства просто посмотрите на вывод asm вашего компилятора для введенного вами кода (все комментарии мои):

mov     dword ptr [rbp - 8], 0    ; i = 0;
cmp     dword ptr [rbp - 8], 0    ; i == 0?
sete    al                        ; TRUE (=1)
mov     cl, al
and     cl, 1                     ; = operator always TRUE
movzx   edx, cl
mov     dword ptr [rbp - 8], edx  ; set i=TRUE;
test    al, 1                     ; al never changed,
                                  ; so final ans is TRUE

Вывод asm, приведенный выше, был из CLANG, но все остальные компиляторы, на которые я смотрел, выдавали похожий вывод.

Обратите внимание, что ваш компилятор на самом деле не установил i = 1, но i = TRUE.Это связано с тем, что оператор && только оценивает, является ли оператор TRUE или FALSE, а затем устанавливает результаты в соответствии с этим результатом.В качестве доказательства попробуйте изменить i = 1 на i = 2, и вы сами сможете убедиться, что ничего не изменится.Убедитесь сами, используя любой онлайн-компилятор на Compiler Explorer

0 голосов
/ 28 мая 2019

Это связано с разбором правил справа налево.Например, у = х + 5.
Все подвыражения имеют важность по важности.Два выражения одинаковой важности оцениваются справа налево.Сначала выполняется сторона выражения &&, затем LHS.

Имеет смысл для меня.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...