Почему этот оператор if, объединяющий присваивание и проверку на равенство, возвращает true?

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

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

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

Ответ 1

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

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.

Ответ 2

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

#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.

Ответ 3

Вопрос вводит в заблуждение.

В операторе if "вы не совмещаете присваивание и проверку на равенство".

Как уже объяснялось другими, вы просто присваиваете результат комбинации двух истинных выражений переменной.

Это как спрашивать:

так как "4 + 5 * 2" (по моему мнению...) равно 18 почему

int i = 4 + 5 * 2;
std::cout << i;

печатает 14?

Ответ 4

У вас есть i = 1 меняет значение i на 1. Все значения, отличные от 0 каста для типа bool, дают true. Так что у тебя всегда есть правда.

Ответ 5

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

  1. Компилятор присваивает приоритет "i == 0", что соответствует истине.
  2. Затем он будет оценивать i = 1 как TRUE или FALSE, и поскольку скомпилированные операторы присваивания никогда не завершаются ошибкой (иначе они не будут компилироваться), он также оценивается как true.
  3. Поскольку оба утверждения оцениваются как истинные, и 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, но все остальные компиляторы, на которые я смотрел, давали похожий вывод. Это верно для всех компиляторов на этом сайте, будь то чистые компиляторы C или C++, все без каких-либо прагм для изменения режима компилятора (который по умолчанию равен C++ для компиляторов C++)

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

Ответ 6

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

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